Magento CatalogSearch-Architektur im Detail verstehen
AI generated
_doc
_index
Magento · CatalogSearch · Elasticsearch · Architektur
Magento CatalogSearch-Architektur im Detail
vom Produktattribut zum Elasticsearch-Dokument

Die Magento CatalogSearch-Architektur wirkt von aussen wie eine Blackbox: Man aktualisiert ein Attribut, wartet auf den Reindex und hofft, dass die Suche das richtige Ergebnis liefert. Wer versteht, wie Indexer, Fulltext-Scope-Tabellen und der Elasticsearch-Adapter zusammenspielen, kann gezielt debuggen, erweitern und Performance-Probleme an der richtigen Stelle loesen statt am Symptom.

19 Min. Lesezeit Indexer · FieldMapper · Fulltext-Scope · Search-Request Magento 2.4.x · Elasticsearch 8.x · OpenSearch 2.x

1. CatalogSearch als Architektur, nicht als Feature

Magento CatalogSearch ist der Sammelbegriff fuer alle Komponenten, die eine Produktsuche in Magento ermoeglichen: Indexer, Datenbank-Zwischentabellen, Feldmapping-Klassen, Query-Builder und der eigentliche Elasticsearch- oder OpenSearch-Cluster. Wer CatalogSearch nur als Konfigurationsschalter unter Stores > Configuration > Catalog > Catalog Search betrachtet, uebersieht, dass hinter diesem Schalter eine mehrstufige Pipeline steckt, die bei jedem Attribut-Update, jeder Preisaenderung und jedem neuen Produkt angestossen wird. Diese Pipeline zu verstehen ist der Unterschied zwischen Trial-and-Error-Debugging und gezieltem Eingriff an der richtigen Stelle.

Die CatalogSearch-Architektur in Magento trennt bewusst zwei Zustaendigkeiten: Auf der einen Seite steht die Indexierung, die Produktdaten aus dem EAV-Modell in ein durchsuchbares Format transformiert und an den Suchcluster sendet. Auf der anderen Seite steht die Suchanfrage selbst, die aus einem Nutzer-Query-String einen strukturierten Elasticsearch-Request baut und die Ergebnisse zurueck in Magento-Objekte uebersetzt. Beide Seiten sind ueber Interfaces entkoppelt, sodass Magento theoretisch mit jedem Suchmodul arbeiten koennte, das dieselben Contracts implementiert. In der Praxis ist Elasticsearch beziehungsweise OpenSearch seit Magento 2.4 die einzige unterstuetzte produktive Engine.

Dieser Artikel folgt der CatalogSearch-Architektur entlang ihres natuerlichen Datenflusses: von den beteiligten Modulen ueber die Indexer-Pipeline und die Fulltext-Scope-Tabelle bis zum fertigen Elasticsearch-Dokument, und anschliessend zurueck vom Suchformular ueber den Query-Builder bis zum gerenderten Ergebnis. Wer diesen Weg einmal komplett nachvollzogen hat, kann jede Stelle gezielt erweitern, ohne die gesamte Pipeline neu zu erfinden.

2. Die Elasticsearch-Module im Ueberblick

Magento liefert die Elasticsearch-Integration nicht als ein einzelnes Modul, sondern als eine Schicht aus mehreren aufeinander aufbauenden Modulen. Magento_Elasticsearch enthaelt die generischen, engine-unabhaengigen Grundklassen: Interfaces fuer FieldMapper, Query-Builder und Adapter. Darauf setzen versionsspezifische Module wie Magento_Elasticsearch7 und Magento_OpenSearch auf, die die konkreten Client-Bibliotheken kapseln und versionsspezifische Eigenheiten der jeweiligen Such-Engine abfangen. Welche Engine tatsaechlich aktiv ist, legt die Konfiguration catalog/search/engine fest, typischerweise auf den Wert elasticsearch7 oder opensearch gesetzt.

Diese Modultrennung in der CatalogSearch-Architektur hat einen praktischen Grund: Elasticsearch und OpenSearch unterscheiden sich in Details der Request-Syntax, in unterstuetzten Aggregationstypen und in der Versionierung der Client-Bibliotheken. Statt diese Unterschiede mit Versionsabfragen im Code zu verstreuen, kapselt Magento sie in austauschbaren Modulen, die ueber di.xml-Preferences und virtuelle Typen eingebunden werden. Ein Wechsel der Engine bedeutet im Idealfall nur eine Konfigurationsaenderung plus vollstaendigen Reindex, nicht einen Code-Umbau.

Fuer eigene Erweiterungen der CatalogSearch-Architektur ist wichtig zu wissen, dass die meisten Anpassungspunkte in Magento_Elasticsearch liegen und damit engine-unabhaengig funktionieren. FieldMapper, BatchDataMapper und die meisten Query-Builder-Klassen sind generisch gehalten. Nur wenn tatsaechlich Engine-spezifisches Verhalten benoetigt wird, etwa ein OpenSearch-spezifischer Analyzer, muss man in den versionsspezifischen Modulen ansetzen.


<!-- app/code/Mironsoft/SearchExtension/etc/di.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <!-- Register a custom field mapper that decorates the default one -->
    <type name="Magento\Elasticsearch\Model\Adapter\FieldMapperInterface">
        <plugin name="mironsoft_custom_field_mapper"
                type="Mironsoft\SearchExtension\Plugin\FieldMapperPlugin"
                sortOrder="10"/>
    </type>

    <!-- Preference example: swap the default batch size provider -->
    <preference for="Magento\Elasticsearch\Model\Config"
                type="Mironsoft\SearchExtension\Model\Config"/>
</config>

3. Die Indexer-Pipeline: vom EAV-Attribut zum Dokument

Der zentrale Indexer der CatalogSearch-Architektur traegt den Code catalogsearch_fulltext und wird sowohl bei Attribut-Updates als auch bei Preis- oder Bestandsaenderungen ueber das Magento-Indexer-Framework angestossen. Ausgeloest wird er entweder synchron bei "Update on Save" oder asynchron ueber die Message-Queue bei "Update by Schedule", der in Produktivumgebungen ueblichen Einstellung. In beiden Faellen laeuft dieselbe Kernlogik: Ein Action-Objekt sammelt fuer eine Menge von Produkt-IDs alle relevanten Attributwerte je Store View, baut daraus strukturierte Datensaetze und uebergibt sie an die Such-Engine-Schicht.

Der erste Schritt dieser Pipeline ist rein datenbankseitig: Magento liest EAV-Werte ueber mehrere Attribut-Tabellen (catalog_product_entity_varchar, _int, _decimal, _text, _datetime) aus und fuehrt sie fuer jedes Produkt zu einem flachen Datensatz zusammen. Diese Zusammenfuehrung ist bewusst store-view-spezifisch, weil Attributwerte in Magento pro Store View ueberschrieben werden koennen. Erst nach diesem Join entsteht die Datenstruktur, die anschliessend von den FieldMapper- und BatchDataMapper-Klassen in Elasticsearch-Feldnamen und -Werte uebersetzt wird.

Wichtig fuer das Verstaendnis der CatalogSearch-Architektur: Der Indexer arbeitet grundsaetzlich in Batches, deren Groesse ueber die Konfiguration catalog/search/elasticsearch7_indexer_batch_size steuerbar ist. Bei sehr grossen Katalogen mit hunderttausenden Produkten ist diese Batch-Groesse ein zentraler Stellhebel: Zu grosse Batches ueberlasten den Bulk-Endpunkt von Elasticsearch, zu kleine Batches verlaengern die Gesamtlaufzeit durch zu viele HTTP-Roundtrips.

4. Die Fulltext-Scope-Tabelle als Zwischenschicht

Ein oft uebersehener Baustein der CatalogSearch-Architektur ist die Fulltext-Scope-Tabelle, in Magento als catalogsearch_fulltext_scope<store_id> pro Store View angelegt. Diese Tabelle fungiert als Zwischenspeicher zwischen dem reinen EAV-Datenzugriff und der eigentlichen Uebertragung an Elasticsearch. Der Grund fuer diese Zwischenschicht ist historisch: Magentos Suchindex-Framework wurde urspruenglich engine-unabhaengig konzipiert, sodass auch die native MySQL-Volltextsuche denselben Datenfluss nutzen konnte. Auch wenn MySQL-Suche in aktuellen Magento-Versionen keine unterstuetzte Produktivoption mehr ist, bleibt die Scope-Tabelle als Bestandteil der Indexer-Pipeline bestehen.

Innerhalb dieser Scope-Tabelle liegen die aufbereiteten, store-view-spezifischen Textdaten je Produkt, bereits mit den durchsuchbaren Attributwerten zu einem searchable-Textblock zusammengefuehrt. Erst aus dieser Zwischenschicht liest der Elasticsearch-Adapter die Datensaetze, die anschliessend in Bulk-Requests an den Suchcluster gesendet werden. Wer die Fulltext-Scope-Tabelle direkt inspiziert, etwa via SELECT * FROM catalogsearch_fulltext_scope1 LIMIT 5, sieht damit exakt den Zwischenstand, bevor die Daten das eigentliche Elasticsearch-Mapping durchlaufen.

Diese Zwischenschicht der CatalogSearch-Architektur ist auch der Ort, an dem sich viele Reindex-Probleme diagnostizieren lassen: Fehlt ein Produkt im Suchergebnis, obwohl es aktiv und sichtbar ist, lohnt sich zuerst der Blick in die Scope-Tabelle. Ist der Datensatz dort bereits nicht vorhanden, liegt das Problem in der EAV-Datenaufbereitung, nicht im Elasticsearch-Mapping oder im Query-Builder. Diese Unterscheidung spart bei der Fehlersuche erheblich Zeit.


# Inspect the intermediate fulltext scope table for store id 1
bin/mysql -e "SELECT entity_id, data_index FROM catalogsearch_fulltext_scope1 WHERE entity_id = 12345\G"

# Check whether the indexer is scheduled and its current status
bin/magento indexer:status catalogsearch_fulltext

# Trigger a full reindex for CatalogSearch only
bin/magento indexer:reindex catalogsearch_fulltext

5. Von Attribut zu Feld: der FieldMapper

Sobald Produktdaten die Fulltext-Scope-Zwischenschicht durchlaufen haben, uebernimmt der FieldMapper die Uebersetzung von Magento-Attributcodes in Elasticsearch-Feldnamen. Dieser Schritt ist zentral fuer die CatalogSearch-Architektur, weil er entscheidet, unter welchem Feldnamen und mit welchem Elasticsearch-Datentyp ein Attribut im Index landet. Die Klasse Magento\Elasticsearch\Model\Adapter\FieldMapper implementiert FieldMapperInterface und wird ueber eine FieldMapperResolver-di.xml-Konfiguration je nach Kontext (Produktindex oder Quick-Search) unterschiedlich zusammengesetzt.

Der Feldtyp selbst wird nicht willkuerlich vergeben, sondern aus dem EAV-Backend-Type des Attributs abgeleitet: Ein varchar-Attribut wird typischerweise zu einem text-Feld mit zusaetzlichem keyword-Sub-Feld, ein decimal-Attribut zu einem numerischen Feld, ein datetime-Attribut zu einem date-Feld. Diese Ableitung passiert in den FieldType-Resolver-Klassen, die ueber di.xml als Array registriert sind und pro Backend-Type eine passende Elasticsearch-Typdefinition liefern.


<?php
declare(strict_types=1);

namespace Mironsoft\SearchExtension\Plugin;

use Magento\Elasticsearch\Model\Adapter\FieldMapperInterface;

/**
 * Adds a custom prefix for attributes flagged as "b2b_only"
 * before they reach the Elasticsearch mapping resolver.
 */
class FieldMapperPlugin
{
    /**
     * Intercepts the field name resolution to apply custom naming rules.
     *
     * @param FieldMapperInterface $subject
     * @param string $result
     * @param string $attributeCode
     * @param array $context
     * @return string
     */
    public function afterGetFieldName(
        FieldMapperInterface $subject,
        string $result,
        string $attributeCode,
        array $context = []
    ): string {
        if ($attributeCode === 'b2b_only_price') {
            return 'b2b_price_filter';
        }

        return $result;
    }
}

6. Die Search-Request-Pipeline im Detail

Waehrend die Indexer-Pipeline Daten in Elasticsearch schreibt, ist die Search-Request-Pipeline fuer den umgekehrten Weg zustaendig: Ein Nutzer-Query-String wird ueber Magento\Elasticsearch\SearchAdapter\Query\Builder in einen strukturierten Elasticsearch-Request uebersetzt. Diese Builder-Klasse kombiniert den eigentlichen Suchbegriff mit Filterbedingungen aus der Layered Navigation, mit Store-View-Kontext und mit Sichtbarkeitsregeln, sodass am Ende ein vollstaendiger Bool-Query-Body entsteht, der sowohl must- als auch filter-Klauseln enthaelt.

Nach dem Absenden des Requests verarbeitet der SearchAdapter die Elasticsearch-Antwort und uebersetzt Treffer-IDs zurueck in ein SearchResult-Objekt, das Magento anschliessend fuer die Produktliste verwendet. Wichtig in dieser CatalogSearch-Architektur: Elasticsearch liefert nur Entity-IDs und Scores zurueck, keine vollstaendigen Produktdaten. Magento laedt die tatsaechlichen Produktdaten anschliessend ganz normal ueber die Produkt-Collection aus der Datenbank, gefiltert auf die von Elasticsearch gelieferten IDs. Diese Trennung haelt den Suchindex schlank und vermeidet, dass Produktdaten dupliziert an zwei Stellen gepflegt werden muessen.


GET /magento2_product_1_v1/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "wireless kopfhoerer",
            "fields": ["name^3", "sku^7", "description^1", "short_description^2"],
            "type": "cross_fields"
          }
        }
      ],
      "filter": [
        { "term": { "visibility": 4 } },
        { "term": { "status": 1 } },
        { "term": { "store_id": 1 } }
      ]
    }
  },
  "from": 0,
  "size": 24
}

7. Full-Reindex vs. Schedule: wann was greift

Die CatalogSearch-Architektur unterstuetzt zwei grundsaetzlich unterschiedliche Aktualisierungswege. Der vollstaendige Reindex baut den kompletten Index neu auf: Ein neuer Elasticsearch-Index mit inkrementiertem Versionssuffix wird angelegt, alle Produkte werden neu geschrieben, und erst am Ende wird der Alias auf den neuen Index umgeschaltet. Dieser Ansatz garantiert Konsistenz, ist aber bei grossen Katalogen ressourcenintensiv und dauert entsprechend lange.

Der partielle Reindex, ausgeloest ueber "Update by Schedule", verarbeitet dagegen nur die Produkt-IDs, die sich seit dem letzten Lauf tatsaechlich geaendert haben. Diese IDs werden ueber ein Changelog-System gesammelt, das Magento bei jedem relevanten Datenbank-Save automatisch befuellt. Ein Cron-Job verarbeitet dieses Changelog in konfigurierbaren Intervallen und aktualisiert nur die betroffenen Dokumente im bestehenden Index, ohne einen neuen Index anzulegen. Das ist fuer den Produktivbetrieb der bevorzugte Modus, weil Aenderungen zeitnah sichtbar werden, ohne die Systemlast eines vollstaendigen Reindex zu erzeugen.

Komponente Aufgabe Zentrale Klasse Ausgeloest durch
Fulltext-Indexer EAV-Daten sammeln und je Store View zusammenfuehren Indexer\Fulltext\Action\Full Reindex-Aufruf, Cron
Scope-Tabelle Zwischenspeicher fuer aufbereitete Textdaten je Store catalogsearch_fulltext_scope<id> Indexer-Lauf
FieldMapper Attributcode in Elasticsearch-Feldname und -Typ uebersetzen Adapter\FieldMapper Vor jedem Bulk-Request
BatchDataMapper Rohdaten in Bulk-Dokumentstruktur packen ProductFieldsMapper Batch-Verarbeitung
Query-Builder Nutzer-Query in Bool-Query uebersetzen SearchAdapter\Query\Builder Jede Suchanfrage

8. Diagnose: die tatsaechliche Elasticsearch-Query sichtbar machen

Ein haeufiger Frustpunkt in der CatalogSearch-Architektur ist, dass Magento standardmaessig nicht anzeigt, welche Query tatsaechlich an Elasticsearch gesendet wurde. Debugging findet deshalb oft ueber Umwege statt. Der zuverlaessigste Weg ist, den HTTP-Traffic zwischen Magento und dem Suchcluster mitzuschneiden, etwa ueber einen Reverse Proxy mit Logging oder ueber den Slowlog von Elasticsearch selbst, der auch schnelle Queries protokollieren kann, wenn die Schwellenwerte entsprechend niedrig gesetzt werden.

Alternativ laesst sich das Query-Builder-Objekt gezielt per Plugin abfangen und die generierte Query in ein Logfile schreiben, bevor sie an den Client uebergeben wird. Dieser Ansatz ist invasiver, liefert aber die exakte Query ohne Netzwerk-Sniffing und ist besonders hilfreich, wenn man vermutet, dass ein Custom-FieldMapper die Query in einer unerwarteten Weise beeinflusst. In Kombination mit der Elasticsearch-_explain-API laesst sich anschliessend nachvollziehen, warum ein bestimmtes Dokument fuer eine Query gar nicht oder mit unerwartet niedrigem Score getroffen wird.


POST /magento2_product_1_v1/_explain/12345
{
  "query": {
    "multi_match": {
      "query": "wireless kopfhoerer",
      "fields": ["name^3", "sku^7", "description^1"]
    }
  }
}

9. Praxisbeispiel: eigene Indexer-Erweiterung

Ein realistisches Beispiel fuer eine Erweiterung der CatalogSearch-Architektur ist das Anreichern des Suchindex um berechnete Werte, die nicht direkt als Produktattribut existieren, etwa ein "Beliebtheits-Score" aus Bestelldaten. Anstatt diesen Wert als klassisches EAV-Attribut zu pflegen, laesst er sich direkt in der Indexer-Pipeline berechnen und als zusaetzliches Feld in das Elasticsearch-Dokument einfuegen, ohne die Datenbankstruktur zu veraendern.

Dazu wird ein Plugin auf die BatchDataMapper-Klasse gesetzt, das nach der Standard-Feldzusammenstellung den berechneten Score ergaenzt. Wichtig dabei: Der neue Feldname muss auch im Elasticsearch-Mapping als eigenstaendiges Feld angelegt sein, sonst greift die dynamische Mapping-Erkennung von Elasticsearch, die nicht immer den gewuenschten Feldtyp waehlt. Ein expliziter Mapping-Eintrag vor dem naechsten vollstaendigen Reindex verhindert diese Unsicherheit zuverlaessig.

Diese Art von Erweiterung zeigt den eigentlichen Vorteil der modularen CatalogSearch-Architektur: Man muss weder den Indexer noch den Query-Builder komplett neu implementieren, sondern setzt gezielt an einem klar definierten Erweiterungspunkt an, ohne die Kompatibilitaet mit Magento-Core-Updates zu gefaehrden.

Mironsoft

Magento CatalogSearch, Elasticsearch und OpenSearch Beratung

Magento-Suche, die technisch nachvollziehbar bleibt?

Wir analysieren eure CatalogSearch-Architektur, finden die Ursache fehlender Treffer und bauen Custom-FieldMapper und Indexer-Erweiterungen, die mit jedem Magento-Update kompatibel bleiben.

Architektur-Audit

Indexer, FieldMapper und Query-Builder auf Schwachstellen pruefen

Custom-Erweiterungen

Eigene FieldMapper und Indexer-Plugins fuer spezifische Anforderungen

Performance-Tuning

Batch-Groessen, Reindex-Strategien und Cluster-Konfiguration optimieren

10. Zusammenfassung

Die Magento CatalogSearch-Architektur ist kein einzelner Konfigurationsschalter, sondern eine mehrstufige Pipeline aus Indexer, Fulltext-Scope-Zwischenschicht, FieldMapper und Search-Request-Builder. Produktdaten durchlaufen bei der Indexierung mehrere klar getrennte Stufen, bevor sie als Elasticsearch-Dokument landen, und derselbe Weg wird bei jeder Suchanfrage in umgekehrter Richtung durchlaufen, um aus Nutzereingaben strukturierte Elasticsearch-Queries zu bauen.

Wer diese CatalogSearch-Architektur versteht, findet Fehlerquellen deutlich schneller: Fehlt ein Produkt im Ergebnis, prueft man zuerst die Scope-Tabelle, dann das Mapping, dann den Query-Builder. Erweiterungen wie eigene FieldMapper-Plugins oder zusaetzliche berechnete Felder lassen sich gezielt an klar definierten Erweiterungspunkten anbringen, ohne die Kernlogik des Indexers zu veraendern. Genau diese Trennschaerfe macht die Architektur trotz ihrer Komplexitaet wartbar.

Magento CatalogSearch-Architektur: das Wichtigste auf einen Blick

Indexer-Pipeline

EAV-Daten werden je Store View zusammengefuehrt, in die Fulltext-Scope-Tabelle geschrieben und batchweise an Elasticsearch gesendet.

FieldMapper

Uebersetzt Attributcodes anhand des EAV-Backend-Types in Elasticsearch-Feldnamen und -Datentypen.

Reindex-Modi

Full-Reindex baut den Index komplett neu, Update by Schedule aktualisiert nur geaenderte Produkt-IDs ueber ein Changelog.

Erweiterbarkeit

FieldMapper- und BatchDataMapper-Plugins erlauben Custom-Felder, ohne den Indexer-Kern zu veraendern.

11. FAQ: Magento CatalogSearch-Architektur

1Was macht der catalogsearch_fulltext Indexer?
Sammelt EAV-Attributwerte je Store View, fuehrt sie zusammen, schreibt sie in die Scope-Tabelle und sendet sie batchweise an Elasticsearch.
2Wozu dient die Fulltext-Scope-Tabelle?
Store-view-spezifische Zwischenschicht vor der Uebertragung an Elasticsearch. Erster Anlaufpunkt bei fehlenden Suchtreffern.
3Elasticsearch vs. Elasticsearch7 Modul?
Generische Basis versus versionsspezifische Client-Kapselung. Die meisten Erweiterungen setzen an der generischen Basis an.
4Wie wird der Feldtyp bestimmt?
Aus dem EAV-Backend-Type: varchar zu text plus keyword, decimal zu numerisch, datetime zu date.
5Full-Reindex oder Schedule?
Full nach Mapping-Aenderungen oder Massenimport, Schedule fuer den laufenden Produktivbetrieb.
6Wie sehe ich die echte ES-Query?
Traffic-Mitschnitt, Slowlog mit niedriger Schwelle oder ein Logging-Plugin auf den Query-Builder.
7Eigene berechnete Felder moeglich?
Ja, per Plugin auf BatchDataMapper, mit passendem expliziten Mapping-Eintrag.
8Warum nur IDs statt Produktdaten?
Schlanker Index, keine doppelte Datenpflege. Produktdaten laedt Magento anschliessend aus der Datenbank.
9Was steuert die Batch-Groesse?
catalog/search/elasticsearch7_indexer_batch_size. Balance zwischen Bulk-Last und Roundtrip-Anzahl.
10Wo Custom-Mapping ansetzen?
Am FieldMapperInterface bzw. per Plugin darauf, engine-unabhaengig und update-sicher.