Welche Requests gehen an MySQL, welche an OpenSearch? Wie synchronisiert Magento Produktdaten, warum kommen Layered-Navigation-Filter aus OpenSearch — und wie debuggt man fehlende Produkte in der Suche?
Inhaltsverzeichnis
- 1. Die Zwei-Datenbank-Architektur in Magento verstehen
- 2. Was kommt aus MySQL: Kategorieseiten, PDP, Cart, Checkout
- 3. Was kommt aus OpenSearch: Suche und Suchvorschläge
- 4. Der Sync-Prozess: MySQL zu OpenSearch
- 5. Der catalogsearch_fulltext Indexer im Detail
- 6. Die catalogsearch_fulltext Tabelle — Legacy-Überbleibsel
- 7. Warum Magento von MySQL FULLTEXT zu OpenSearch gewechselt hat
- 8. Layered Navigation kommt aus OpenSearch-Aggregationen
- 9. Debugging: Produkt erscheint nicht in der Suche
- 10. Unterstützung
- 11. Zusammenfassung
- 12. FAQ
1. Die Zwei-Datenbank-Architektur in Magento verstehen
Magento OpenSearch MySQL ist keine Frage von entweder-oder, sondern von Arbeitsteilung. Magento verwendet zwei Datenspeicher parallel: MySQL für persistente Stammdaten (Produkte, Kategorien, Bestellungen, Kundendaten) und OpenSearch (oder Elasticsearch) als spezialisierte Suchmaschine für Suchanfragen, Facettenfilter und Suchvorschläge. Beide Systeme müssen konsistent bleiben — das geschieht über den Indexer-Mechanismus.
Das Wichtigste für den Shopbetrieb: Wenn ein Produkt in MySQL gespeichert ist, bedeutet das nicht, dass es in der Suche erscheint. Es muss zuerst über den catalogsearch_fulltext Indexer in OpenSearch synchronisiert worden sein. Umgekehrt: Wenn OpenSearch-Daten veraltet sind, zeigt die Suche alte Preise oder nicht vorhandene Produkte.
2. Was kommt aus MySQL: Kategorieseiten, PDP, Cart, Checkout
MySQL ist die primäre Datenquelle für alle strukturierten Datenzugriffe in Magento. Kategorieseiten nutzen zwar OpenSearch für die Produktliste (wenn OpenSearch konfiguriert ist), aber die Kategorie-Metadaten, die Breadcrumb-Struktur und die CMS-Inhalte kommen aus MySQL. Die Produktdetailseite (PDP) liest alle Produktdaten ausschließlich aus MySQL — EAV-Attribute, Preis, Lagerbestand, Bilder.
-- Produktdetailseite: Magento liest Attributwerte aus EAV-Tabellen (MySQL)
SELECT
e.entity_id,
e.sku,
ev_name.value AS name,
ev_desc.value AS description,
ev_price.value AS price
FROM catalog_product_entity e
LEFT JOIN catalog_product_entity_varchar ev_name
ON ev_name.entity_id = e.entity_id
AND ev_name.attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'name')
AND ev_name.store_id = 0
LEFT JOIN catalog_product_entity_text ev_desc
ON ev_desc.entity_id = e.entity_id
AND ev_desc.attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'description')
AND ev_desc.store_id = 0
LEFT JOIN catalog_product_entity_decimal ev_price
ON ev_price.entity_id = e.entity_id
AND ev_price.attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'price')
AND ev_price.store_id = 0
WHERE e.entity_id = 42;
-- Cart und Checkout: quote-Tabellen kommen vollständig aus MySQL
SELECT q.entity_id, q.grand_total, qi.sku, qi.qty, qi.row_total
FROM quote q
JOIN quote_item qi ON qi.quote_id = q.entity_id
WHERE q.is_active = 1
AND q.customer_id = 1234;
-- Kategorie-Struktur: catalog_category_entity (MySQL)
SELECT entity_id, path, level, children_count, name
FROM catalog_category_flat_store_1
WHERE is_active = 1
AND level BETWEEN 2 AND 4
ORDER BY position;
3. Was kommt aus OpenSearch: Suche und Suchvorschläge
Sobald ein Nutzer eine Suchanfrage im Shop stellt, geht die Anfrage nicht an MySQL, sondern direkt an OpenSearch. Das gilt für die Suchergebnisseite, Suchvorschläge (Autocomplete) und — wenn OpenSearch als Quelle konfiguriert ist — auch für Kategorieseiten mit Layered Navigation. Magento übersetzt die eingehende Suchanfrage in eine OpenSearch-Query, holt die Produkt-IDs zurück und lädt dann die vollständigen Produktdaten aus MySQL.
-- Magento-Suchablauf vereinfacht:
-- 1. Nutzer sucht nach "rotes Hemd"
-- 2. Magento sendet Query an OpenSearch:
-- GET /magento2_product_1/_search
-- { "query": { "bool": { "should": [...] } }, "aggs": {...} }
-- 3. OpenSearch gibt Produkt-IDs zurück: [42, 17, 89, ...]
-- 4. Magento lädt Produktdaten aus MySQL für diese IDs
-- Schritt 4 in SQL:
SELECT
e.entity_id,
ev.value AS name,
ep.value AS price
FROM catalog_product_entity e
JOIN catalog_product_entity_varchar ev
ON ev.entity_id = e.entity_id
AND ev.attribute_id = 73 -- name
AND ev.store_id = 1
JOIN catalog_product_entity_decimal ep
ON ep.entity_id = e.entity_id
AND ep.attribute_id = 64 -- price
AND ep.store_id = 0
WHERE e.entity_id IN (42, 17, 89, 103, 55) -- IDs aus OpenSearch
ORDER BY FIELD(e.entity_id, 42, 17, 89, 103, 55); -- Relevanz-Sortierung beibehalten
-- Suchvorschläge: catalogsearch_query (MySQL-Cache für häufige Suchanfragen)
SELECT query_text, num_results, popularity
FROM catalogsearch_query
WHERE store_id = 1
ORDER BY popularity DESC
LIMIT 20;
4. Der Sync-Prozess: MySQL zu OpenSearch
Der Sync-Prozess zwischen MySQL und OpenSearch erfolgt über Magento's Indexer-System. Wenn Produktdaten in MySQL geändert werden (über Admin, Import oder API), werden die betroffenen Produkte als "invalid" markiert. Der catalogsearch_fulltext Indexer liest dann die aktuellen Daten aus den EAV-Tabellen, transformiert sie in ein flaches Dokument und pusht es an OpenSearch.
-- Indexer-Status prüfen (MySQL-Tabelle mview_state)
SELECT indexer_id, status, updated, action_groups
FROM mview_state
WHERE indexer_id = 'catalogsearch_fulltext';
-- Oder über die indexer_state Tabelle
SELECT indexer_id, status, updated
FROM indexer_state
WHERE indexer_id = 'catalogsearch_fulltext';
-- Welche Produkte warten auf Re-Indexierung?
SELECT DISTINCT source_entity_id AS product_id
FROM catalogsearch_fulltext_cl
ORDER BY version_id DESC
LIMIT 50;
-- Magento CLI: Indexer-Status prüfen
-- bin/magento indexer:status catalogsearch_fulltext
-- Magento CLI: Vollständige Neuindexierung
-- bin/magento indexer:reindex catalogsearch_fulltext
-- Wie viele Produkte sind im OpenSearch-Index?
-- bin/magento catalog:search:index:show (zeigt Index-Informationen)
-- Oder direkt über OpenSearch REST API:
-- curl http://opensearch:9200/magento2_product_1/_count
5. Der catalogsearch_fulltext Indexer im Detail
Der catalogsearch_fulltext Indexer ist das Herzstück der Magento OpenSearch MySQL Synchronisation. Er liest für jedes zu indizierende Produkt aus den EAV-Tabellen alle als is_searchable = 1 markierten Attributwerte, kombiniert sie mit Preis-, Lagerbestand- und Kategorie-Informationen und erstellt ein JSON-Dokument, das an OpenSearch gesendet wird.
-- Welche Attribute werden in OpenSearch indiziert?
SELECT
a.attribute_id,
a.attribute_code,
a.frontend_label,
ai.is_searchable,
ai.is_filterable,
ai.is_filterable_in_search,
ai.used_for_sort_by
FROM eav_attribute a
JOIN catalog_eav_attribute ai ON ai.attribute_id = a.attribute_id
WHERE a.entity_type_id = (SELECT entity_type_id FROM eav_entity_type WHERE entity_type_code = 'catalog_product')
AND ai.is_searchable = 1
ORDER BY a.attribute_code;
-- Wichtiges Feld: is_searchable = 1 bedeutet: Attributwert geht in OpenSearch
-- is_filterable = 1/2 bedeutet: Attribut erscheint in Layered Navigation
-- Beispiel: Alle suchbaren Varchar-Attribute eines Produkts
SELECT
a.attribute_code,
av.value
FROM catalog_product_entity_varchar av
JOIN eav_attribute a ON a.attribute_id = av.attribute_id
JOIN catalog_eav_attribute ai ON ai.attribute_id = av.attribute_id
WHERE av.entity_id = 42
AND av.store_id IN (0, 1)
AND ai.is_searchable = 1
ORDER BY a.attribute_code;
6. Die catalogsearch_fulltext Tabelle — Legacy-Überbleibsel
Magento enthält noch die Tabelle catalogsearch_fulltext, die aus der Zeit stammt, als MySQL's eingebauter FULLTEXT-Index als Suchbackend verwendet wurde. Wenn OpenSearch oder Elasticsearch konfiguriert ist, wird diese Tabelle nicht mehr für Suchanfragen genutzt. Sie bleibt im Schema erhalten, wird aber leer oder ignoriert. Für die Suche relevant ist in diesem Fall ausschließlich der OpenSearch-Index.
-- catalogsearch_fulltext: Legacy MySQL-Suchtabelle
DESCRIBE catalogsearch_fulltext;
-- Typische Spalten: product_id, store_id, data_index (TEXT mit FULLTEXT-Index)
-- Wenn OpenSearch aktiv ist: Tabelle ist nicht relevant für Suche
SELECT COUNT(*) FROM catalogsearch_fulltext WHERE store_id = 1;
-- Bei aktiver OpenSearch-Konfiguration meist 0 oder veraltet
-- Konfiguriertes Suchbackend prüfen (MySQL Konfigurationstabelle)
SELECT path, value
FROM core_config_data
WHERE path IN (
'catalog/search/engine',
'catalog/search/opensearch_server_hostname',
'catalog/search/opensearch_server_port',
'catalog/search/opensearch_index_prefix'
)
ORDER BY path;
-- Typische Werte:
-- catalog/search/engine = 'opensearch' (oder 'elasticsearch7')
-- catalog/search/opensearch_server_hostname = 'opensearch'
-- catalog/search/opensearch_index_prefix = 'magento2'
7. Warum Magento von MySQL FULLTEXT zu OpenSearch gewechselt hat
MySQL's FULLTEXT-Suche hat fundamentale Skalierungs- und Relevanz-Grenzen. Für kleine Shops funktioniert sie, aber bei Hunderttausenden von Produkten, mehrsprachigen Catalogs und komplexen Facetten-Anforderungen stößt sie schnell an Grenzen. OpenSearch bietet überlegene Relevanz-Scoring durch TF/IDF und BM25, horizontale Skalierbarkeit, Aggregationen für Layered Navigation ohne GROUP BY-Overhead und robuste Facettenfilter mit gleichzeitiger Zählung.
-- MySQL FULLTEXT: Grundlegende Suche (nur noch Legacy/Fallback)
SELECT entity_id, data_index
FROM catalogsearch_fulltext
WHERE MATCH(data_index) AGAINST ('rotes hemd' IN NATURAL LANGUAGE MODE)
AND store_id = 1;
-- Probleme mit MySQL FULLTEXT:
-- 1. Keine Aggregationen für Facetten (muss nachträglich GROUP BY auf MySQL laufen)
-- 2. Kein Relevanz-Boosting nach Attribut (name wichtiger als description)
-- 3. Keine Synonym-Unterstützung
-- 4. Bei großen Katalogen: Performance-Probleme durch Table-Lock bei Reindex
-- OpenSearch-Vorteil: Aggregationen für Layered Navigation
-- Magento sendet z.B.:
-- "aggs": {
-- "color": { "terms": { "field": "color_value", "size": 100 } },
-- "price": { "histogram": { "field": "price", "interval": 50 } }
-- }
-- Ergebnis enthält Buckets MIT Produktzahlen in einer einzigen Anfrage
-- MySQL-Äquivalent (deutlich teurer bei Millionen-Produkt-Katalogen):
SELECT color_value, COUNT(*) AS product_count
FROM catalog_product_index_eav
WHERE attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'color')
AND store_id = 1
GROUP BY color_value
ORDER BY product_count DESC;
8. Layered Navigation kommt aus OpenSearch-Aggregationen
Die Filteroptionen in der Layered Navigation (Sidebar-Filter auf Kategorie- und Suchergebnisseiten) kommen bei aktivem OpenSearch aus OpenSearch-Aggregationen, nicht aus MySQL GROUP BY-Abfragen. Das ist ein wesentlicher Performance-Vorteil: Eine einzige OpenSearch-Anfrage liefert gleichzeitig die Produkt-IDs und alle Facetten-Zählungen. MySQL würde für jedes Filterattribut eine separate GROUP BY-Abfrage benötigen.
-- Welche Attribute sind in der Layered Navigation sichtbar?
SELECT
a.attribute_code,
a.frontend_label,
ai.is_filterable, -- 1 = immer, 2 = nur mit Ergebnissen
ai.is_filterable_in_search,
ai.position
FROM eav_attribute a
JOIN catalog_eav_attribute ai ON ai.attribute_id = a.attribute_id
WHERE a.entity_type_id = (SELECT entity_type_id FROM eav_entity_type WHERE entity_type_code = 'catalog_product')
AND ai.is_filterable > 0
ORDER BY ai.position;
-- Produkt-Attributwerte für Layered Navigation (in OpenSearch indexiert via):
SELECT
pei.entity_id AS product_id,
a.attribute_code,
o.value AS option_value,
o.option_id
FROM catalog_product_index_eav pei
JOIN eav_attribute a ON a.attribute_id = pei.attribute_id
JOIN eav_attribute_option o ON o.option_id = pei.value
AND o.attribute_id = pei.attribute_id
WHERE pei.store_id = 1
AND a.attribute_code = 'color'
LIMIT 30;
-- Preisbereich-Buckets für Layered Navigation aus OpenSearch (kein MySQL nötig)
-- MySQL-Fallback für Preisfilter:
SELECT
FLOOR(price / 50) * 50 AS price_bucket,
COUNT(*) AS product_count
FROM catalog_product_index_price
WHERE website_id = 1
AND customer_group_id = 0
GROUP BY FLOOR(price / 50) * 50
ORDER BY price_bucket;
9. Debugging: Produkt erscheint nicht in der Suche
Ein Produkt ist in MySQL vorhanden, erscheint aber nicht in der Suche — eines der häufigsten Support-Themen in Magento OpenSearch MySQL-Setups. Die Ursachen können auf drei Ebenen liegen: MySQL (Produkt-Attribut-Konfiguration), Indexer (nicht gelaufen oder fehlgeschlagen) oder OpenSearch (Dokument nicht vorhanden oder falsch indiziert).
-- Schritt 1: Produkt in MySQL prüfen
SELECT
e.entity_id,
e.sku,
ev_status.value AS status, -- 1 = enabled
ev_vis.value AS visibility, -- 4 = catalog+search, 3 = search only
ev_name.value AS name
FROM catalog_product_entity e
LEFT JOIN catalog_product_entity_int ev_status
ON ev_status.entity_id = e.entity_id
AND ev_status.attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'status')
AND ev_status.store_id = 0
LEFT JOIN catalog_product_entity_int ev_vis
ON ev_vis.entity_id = e.entity_id
AND ev_vis.attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'visibility')
AND ev_vis.store_id = 0
LEFT JOIN catalog_product_entity_varchar ev_name
ON ev_name.entity_id = e.entity_id
AND ev_name.attribute_id = (SELECT attribute_id FROM eav_attribute WHERE attribute_code = 'name')
AND ev_name.store_id = 0
WHERE e.sku = 'PRODUCT-SKU-123';
-- Status muss 1 (Enabled), Visibility muss 3 oder 4 sein
-- Schritt 2: Produkt im Indexer-Changelog prüfen
SELECT version_id, source_entity_id
FROM catalogsearch_fulltext_cl
WHERE source_entity_id = 42 -- product entity_id
ORDER BY version_id DESC;
-- Schritt 3: Indexer-Status prüfen
SELECT indexer_id, status, updated
FROM indexer_state
WHERE indexer_id = 'catalogsearch_fulltext';
-- Status 'valid' = OK, 'invalid' = Neuindexierung nötig
-- Schritt 4: Suchbare Attribute auf das Produkt prüfen
SELECT
a.attribute_code,
av.value
FROM catalog_product_entity_varchar av
JOIN eav_attribute a ON a.attribute_id = av.attribute_id
JOIN catalog_eav_attribute ai ON ai.attribute_id = av.attribute_id
WHERE av.entity_id = 42
AND ai.is_searchable = 1
AND (av.store_id = 0 OR av.store_id = 1)
AND av.value IS NOT NULL
AND av.value != '';
-- Mindestens name sollte hier auftauchen
-- Schritt 5: OpenSearch-Dokument direkt prüfen
-- curl 'http://opensearch:9200/magento2_product_1/_doc/42'
-- Wenn 404 -> Produkt wurde nicht indiziert
-- Wenn vorhanden -> Prüfen ob search_weight und name korrekt sind
-- Schritt 6: Neuindexierung erzwingen
-- bin/magento indexer:reset catalogsearch_fulltext
-- bin/magento indexer:reindex catalogsearch_fulltext
Mironsoft
Magento OpenSearch MySQL-Probleme analysieren und lösen
Fehlende Produkte in der Suche, veraltete Indexer, schlechte Such-Relevanz oder langsame Layered Navigation — wir analysieren die Ursachen und beheben sie systematisch.
Such-Debugging
Fehlende Produkte, falsche Relevanz und Indexer-Probleme systematisch diagnostizieren
OpenSearch-Optimierung
Such-Relevanz, Synonyme und Analyzer-Konfiguration für Ihren Katalog optimieren
Indexer-Performance
Langsame Reindexierungen beschleunigen und Indexer-Strategie optimieren
11. Zusammenfassung
Magento OpenSearch MySQL — die klare Arbeitsteilung: MySQL hält alle persistenten Stammdaten (Produkte, Kategorien, Bestellungen, Kunden). OpenSearch ist zuständig für Suche, Suchvorschläge und die Aggregationen der Layered Navigation. Der Sync-Prozess läuft über den catalogsearch_fulltext Indexer, der aus EAV-Tabellen liest und JSON-Dokumente nach OpenSearch pusht.
Wenn ein Produkt in der Suche fehlt, ist das fast immer auf eine der drei Ursachen zurückzuführen: falscher Status oder falsche Visibility in MySQL, nicht-gelaufener oder fehlgeschlagener Indexer, oder ein fehlendes/veraltetes Dokument in OpenSearch. Die katalogische Diagnose — MySQL prüfen, Indexer-Status prüfen, OpenSearch-Dokument direkt prüfen — löst in der Praxis 95% dieser Fälle.
Magento OpenSearch MySQL — Das Wichtigste auf einen Blick
MySQL
PDP, Cart, Checkout, Kategoriestruktur, alle EAV-Attributwerte. Die "source of truth" für alle Stammdaten.
OpenSearch
Suchanfragen, Suchvorschläge, Layered-Navigation-Aggregationen. Schneller, aber abgeleiteter Index.
Sync
catalogsearch_fulltext Indexer liest is_searchable Attribute aus MySQL und pusht nach OpenSearch.
Debugging
Status+Visibility in MySQL prüfen → Indexer-Status → OpenSearch-Dokument direkt abrufen.