OS
MAGENTO
Magento · OpenSearch · MySQL · Indexer · Layered Navigation
OpenSearch und MySQL in Magento: Wo die Daten wirklich herkommen

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?

MySQL vs. OpenSearch Request-Split catalogsearch Indexer Layered Navigation Fehlende Produkte debuggen

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.

12. FAQ: Magento OpenSearch MySQL

1 Welche Magento-Requests gehen an MySQL, welche an OpenSearch?
MySQL: Produktdetailseite, Cart, Checkout, Kategoriestruktur, alle CRUD-Operationen. OpenSearch: Suchanfragen, Suchvorschläge, Layered-Navigation-Filter.
2 Wie synchronisiert Magento MySQL und OpenSearch?
Der catalogsearch_fulltext Indexer liest is_searchable Attributwerte aus EAV-Tabellen und pusht JSON-Dokumente an OpenSearch.
3 Warum erscheint ein Produkt nicht in der Suche?
Häufigste Ursachen: Status Disabled oder falsche Visibility in MySQL; Indexer invalid; OpenSearch-Dokument fehlt. Alle drei Ebenen systematisch prüfen.
4 Was ist die catalogsearch_fulltext Tabelle?
Legacy-Überbleibsel aus der MySQL FULLTEXT-Ära. Bei aktivem OpenSearch-Backend nicht mehr für Suchanfragen genutzt.
5 Warum hat Magento MySQL FULLTEXT durch OpenSearch ersetzt?
MySQL FULLTEXT skaliert nicht für große Kataloge, unterstützt keine Aggregationen für Layered Navigation und bietet kein Relevanz-Boosting. OpenSearch löst diese Probleme.
6 Kommen Layered Navigation Filter aus MySQL?
Nein. Bei aktivem OpenSearch kommen Facetten-Zählungen aus OpenSearch-Aggregationen — eine einzige Query liefert Produkt-IDs und alle Filter-Optionen mit Zählungen.
7 Was bedeutet is_searchable bei einem Magento-Attribut?
is_searchable=1 bedeutet: Der Attributwert wird in das OpenSearch-Dokument aufgenommen und ist in der Volltext-Suche findbar.
8 Wie prüfe ich ob ein Produkt in OpenSearch indiziert ist?
Über die REST API: GET /magento2_product_1/_doc/{entity_id}. Bei 404: nicht indiziert — Indexer-Status prüfen und reindex ausführen.
9 Wie oft läuft der catalogsearch Indexer?
Je nach Modus: Auf Zeitplan (Cron), Manuell oder Update bei Speichern. Empfohlen für Produktion: Auf Zeitplan.
10 Was passiert wenn OpenSearch nicht erreichbar ist?
Magento zeigt Fehler auf der Suchergebnisseite und in der Layered Navigation. PDP, Cart und Checkout funktionieren weiterhin normal — sie nutzen nur MySQL.