Elasticsearch/OpenSearch Performance-Tuning für Magento
60fps
ms
Performance · Elasticsearch · OpenSearch · Magento 2
Elasticsearch/OpenSearch Performance-Tuning für Magento
Index-Mapping, Shards und JVM-Heap richtig konfigurieren

Eine falsch konfigurierte Elasticsearch oder OpenSearch Installation bremst jede Kategorieseite und jede Facettensuche in Magento spürbar aus. Dieser Artikel zeigt, wie Index-Mapping, Shard-Größen, JVM-Heap und Query-Muster die tatsächliche Antwortzeit bestimmen, wie man mit der Explain API und Cluster-Health-Checks Engpässe findet, und wie man teure Wildcard- und Fuzzy-Queries in der Layered Navigation vermeidet.

16 Min. Lesezeit Index-Mapping · Shards · JVM-Heap Explain API · Cluster Health · Slow Log

1. Warum Suchperformance direkt über Conversion entscheidet

Jede Kategorieseite, jede Facettensuche und jede Autosuggest-Anfrage in einem Magento-Shop mit Elasticsearch oder OpenSearch läuft über denselben Cluster - und genau dieser Cluster wird bei wachsendem Produktkatalog zum unsichtbaren Flaschenhals. Anders als bei einer langsamen MySQL-Query, die sich meist an einem einzelnen fehlenden Index festmachen lässt, entstehen Suchperformance-Probleme aus dem Zusammenspiel mehrerer Faktoren: falsches Index-Mapping, zu viele oder zu wenige Shards, ein zu knapp bemessener JVM-Heap und teure Query-Typen, die erst unter Last spürbar werden.

Das Tückische: Auf einem Entwicklungssystem mit wenigen hundert Produkten läuft praktisch jede Konfiguration schnell genug. Erst bei realistischer Kataloggröße, paralleler Nutzerlast und regelmäßigen Reindexierungen zeigen sich die Schwachstellen - meist genau dann, wenn der Shop unter Last am wenigsten Ausfallzeit verträgt, etwa im Sale. Wer die Mechanik hinter Mapping, Sharding, Heap und Query-Ausführung versteht, kann Engpässe vorab erkennen, statt sie im Live-Betrieb zu debuggen.

2. Index-Mapping und sein Einfluss auf die Query-Geschwindigkeit

Das Index-Mapping legt fest, wie jedes Feld gespeichert, analysiert und durchsucht wird - und diese Entscheidung wirkt sich direkt auf die Query-Geschwindigkeit aus. Der häufigste Fehler in Magento-Katalogen: Attribute, die nur für Filter (Facetten) genutzt werden, werden als text statt als keyword gemappt. text-Felder durchlaufen einen Analyzer mit Tokenizing, Lowercasing und Stemming, was für Volltextsuche sinnvoll ist, für exakte Filterwerte wie Farbe oder Größe aber unnötigen Overhead erzeugt und Wildcard-artige Workarounds provoziert.

Ebenso wichtig: doc_values deaktivieren für Felder, die nie sortiert oder aggregiert werden, und index: false setzen für Felder, die nur zur Anzeige dienen und nie durchsucht werden - etwa interne SKUs oder Freitextnotizen. Jedes unnötig indexierte Feld vergrößert den Index, verlangsamt Refresh-Zyklen und erhöht den Speicherbedarf des Filesystem-Caches. Ein sauberes Mapping ist damit der wirkungsvollste Hebel, noch vor Hardware-Upgrades, weil es die Datenmenge reduziert, die der Cluster pro Query tatsächlich verarbeiten muss.


{
  "mappings": {
    "properties": {
      "sku": { "type": "keyword" },
      "name": {
        "type": "text",
        "analyzer": "standard",
        "fields": {
          "keyword": { "type": "keyword", "ignore_above": 256 }
        }
      },
      "color": { "type": "keyword", "doc_values": true },
      "internal_note": { "type": "text", "index": false },
      "price": { "type": "scaled_float", "scaling_factor": 100 },
      "created_at": { "type": "date", "doc_values": true },
      "description": { "type": "text", "index_options": "freqs" }
    }
  }
}

3. Shard-Sizing für wachsende Produktkataloge

Shard-Sizing bestimmt, wie ein Index über den Cluster verteilt wird, und hat direkten Einfluss auf Parallelisierung und Overhead. Die verbreitete Faustregel für Magento-Kataloge: Ein Shard sollte zwischen 10 und 50 GB Daten enthalten, niemals darunter. Zu viele kleine Shards, ein klassischer Fehler bei "viel hilft viel"-Konfigurationen, erzeugen unnötigen Verwaltungsaufwand, da jede Query gegen jeden Shard einzeln ausgeführt und die Ergebnisse anschließend zusammengeführt werden müssen.

Für die meisten Magento-Installationen mit einem Katalog unter 5 Millionen Produkten reichen ein bis drei primäre Shards pro Store-View-Index völlig aus. Die Anzahl der Replicas sollte sich an der Lesehäufigkeit orientieren, nicht an Verfügbarkeit allein: Jede Replica verdoppelt praktisch den Speicherbedarf, erhöht aber auch die parallele Query-Kapazität. Eine nachträgliche Änderung der primären Shard-Anzahl erfordert immer eine vollständige Reindexierung über einen neuen Index mit anschließendem Alias-Swap, da die Shard-Zahl nach dem Anlegen eines Index nicht mehr verändert werden kann.


# Create index with tuned shard/replica count for catalog scale
curl -X PUT "http://localhost:9200/catalogsearch_v2" -H 'Content-Type: application/json' -d '
{
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1,
    "refresh_interval": "30s"
  }
}'

# Verify shard distribution and index size at a glance
curl -s "http://localhost:9200/_cat/indices?v&h=index,pri,rep,docs.count,store.size"

# Reindex into the new index, then swap the alias atomically
curl -X POST "http://localhost:9200/_reindex" -H 'Content-Type: application/json' -d '
{
  "source": { "index": "catalogsearch_v1" },
  "dest": { "index": "catalogsearch_v2" }
}'

curl -X POST "http://localhost:9200/_aliases" -H 'Content-Type: application/json' -d '
{
  "actions": [
    { "remove": { "index": "catalogsearch_v1", "alias": "catalogsearch" } },
    { "add": { "index": "catalogsearch_v2", "alias": "catalogsearch" } }
  ]
}'

4. JVM-Heap-Tuning ohne Garbage-Collection-Pausen

Der JVM-Heap ist die zweithäufigste Ursache für unregelmäßige Antwortzeiten. Die Grundregel lautet: maximal 50 % des verfügbaren RAM für den Heap reservieren, den Rest dem Betriebssystem für den Filesystem-Cache überlassen, über den Lucene-Segmente gelesen werden. Ein zu großer Heap ist paradoxerweise schädlich, weil er die Garbage-Collection-Pausen verlängert und dem Betriebssystem weniger Speicher für das Caching der Indexdateien lässt, beides führt zu spürbaren Latenzspitzen.

Eine harte Obergrenze liegt bei etwa 30 bis 32 GB Heap: Oberhalb dieser Schwelle verliert die JVM die "Compressed Ordinary Object Pointers" (Compressed OOPs), wodurch jeder Objektzeiger doppelt so viel Speicher benötigt und der effektiv nutzbare Heap trotz mehr RAM sinkt. -Xms und -Xmx sollten immer identisch gesetzt werden, damit die JVM den Heap nicht zur Laufzeit vergrößert, was selbst kurze Stop-the-World-Pausen verursacht. Für die Garbage Collection empfiehlt sich der G1GC-Collector, der seit Java 9 Standard ist und mit vorhersehbaren Pausenzeiten arbeitet.


## config/jvm.options.d/heap.options
## Heap size must be identical for Xms and Xmx to avoid runtime resizing
-Xms8g
-Xmx8g

## Stay below ~30GB to keep compressed ordinary object pointers enabled
## Use G1GC for predictable, shorter garbage collection pauses
-XX:+UseG1GC
-XX:G1ReservePercent=25
-XX:InitiatingHeapOccupancyPercent=30

## Dump the heap on OutOfMemoryError for post-mortem analysis
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/elasticsearch/heapdump.hprof

5. Query-Profiling mit der Explain API

Die Explain API zeigt für eine einzelne Query und ein einzelnes Dokument exakt, wie der Relevanz-Score zustande kommt und welche Query-Klauseln wie viel Rechenzeit kosten. Statt zu raten, warum eine Facettensuche langsam ist, liefert GET /index/_explain/{doc_id} eine detaillierte Aufschlüsselung jeder Teilberechnung, unverzichtbar, wenn ein Custom-Score-Plugin oder eine komplexe Bool-Query unerwartete Ergebnisse liefert.

Für reine Performance-Analyse ist die Profile API ("profile": true im Request-Body) oft aussagekräftiger als Explain, weil sie die tatsächliche Ausführungszeit jeder Query-Komponente pro Shard misst, statt nur die Score-Berechnung zu erklären. So lässt sich präzise feststellen, ob eine langsame Layered-Navigation-Anfrage an einer teuren Aggregation, einem ineffizienten Filter oder am Netzwerk-Overhead zwischen Koordinator- und Daten-Knoten liegt. Beide APIs sollten nie in Produktion für Live-Traffic aktiv sein, da sie selbst spürbaren Overhead erzeugen, sie gehören ins Staging oder in gezielte Debugging-Sessions.

6. Teure Wildcard- und Fuzzy-Queries in der Layered Navigation vermeiden

Wildcard- und Fuzzy-Queries sind die häufigste Ursache für plötzliche Latenzspitzen in der Layered Navigation. Ein wildcard-Query mit führendem Sternchen wie *schuh* kann von Lucene nicht über den invertierten Index aufgelöst werden und erzwingt stattdessen einen Scan über alle Terms im Feld, bei hoher Kardinalität, etwa bei Freitextattributen, wird das schnell zum linearen Scan über den gesamten Datenbestand.

Die Lösung liegt fast immer in der Indexierungsphase statt in der Query-Phase: Ein edge_ngram-Analyzer erzeugt beim Indexieren bereits alle sinnvollen Präfixe eines Begriffs, sodass eine einfache match-Query zur Suchzeit genügt, statt eine teure Wildcard-Query auszuführen. Ähnlich verhält es sich mit fuzzy-Queries: fuzziness: "AUTO" statt eines festen Edit-Distance-Werts begrenzt die Rechenkosten automatisch anhand der Wortlänge, und die Fuzzy-Suche sollte ausschließlich auf dem eigentlichen Suchfeld laufen, niemals als globaler Fallback über alle Felder gleichzeitig.


<?php

declare(strict_types=1);

namespace Mironsoft\SearchPerformance\Plugin;

use Magento\Elasticsearch\SearchAdapter\QueryContainer;

/**
 * Replaces expensive wildcard filters with term queries against
 * pre-indexed edge-ngram fields for layered navigation search.
 */
class AvoidWildcardQueryPlugin
{
    /**
     * Rewrites a wildcard-style clause into a match query against
     * the "_prefix" sub-field populated by an edge_ngram analyzer.
     *
     * @param QueryContainer $subject
     * @param array $result
     * @return array
     */
    public function afterGetQuery(QueryContainer $subject, array $result): array
    {
        // Detect leading-wildcard patterns injected by legacy filter code
        if (isset($result['wildcard'])) {
            foreach ($result['wildcard'] as $field => $clause) {
                $value = str_replace('*', '', (string) $clause['value']);

                // Route to the pre-indexed prefix field instead of a full scan
                $result['match'][$field . '_prefix'] = ['query' => $value];
                unset($result['wildcard'][$field]);
            }
        }

        return $result;
    }
}

7. Magento-spezifische Suchengine-Konfiguration

Magento konfiguriert die Such-Engine über Stores > Configuration > Catalog > Catalog Search und, für tiefere Eingriffe, über di.xml-Präferenzen im Modul Magento_Elasticsearch7 beziehungsweise Magento_Elasticsearch8 für OpenSearch-kompatible Setups. Die elasticsearch7_server_hostname, _port und _index_prefix-Werte landen in env.php und sollten pro Umgebung getrennt gepflegt werden, damit Staging-Reindexierungen nie versehentlich den Produktions-Index treffen.

Für eigene Query-Logik bietet Magento die SearchAdapterInterface-Erweiterungspunkte sowie Plugins auf Magento\Elasticsearch\SearchAdapter\QueryContainer, um zusätzliche Filter oder Boosting-Regeln einzubauen, ohne den Core-Adapter zu ersetzen. Wichtig für die Performance: bin/magento indexer:reindex catalogsearch_fulltext sollte bei großen Katalogen im Batch-Modus mit angepasster batch_size laufen, da die Standardgröße von 100 Dokumenten pro Bulk-Request bei Millionen Produkten zum Flaschenhals wird, eine Erhöhung auf 1000 bis 5000 reduziert die Anzahl der HTTP-Roundtrips drastisch.


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

    <!-- Increase bulk batch size to reduce HTTP roundtrips on large catalogs -->
    <type name="Magento\Elasticsearch\Model\Adapter\BatchDataMapper\ProductFieldsProvider">
        <arguments>
            <argument name="batchSize" xsi:type="number">2000</argument>
        </arguments>
    </type>

    <!-- Route wildcard cleanup through a dedicated plugin -->
    <type name="Magento\Elasticsearch\SearchAdapter\QueryContainer">
        <plugin name="mironsoft_avoid_wildcard_query"
                type="Mironsoft\SearchPerformance\Plugin\AvoidWildcardQueryPlugin"
                sortOrder="10"/>
    </type>

</config>

8. Cluster-Health überwachen: _cluster/health, _cat/indices, Slow Log

Der schnellste Gesundheitscheck ist GET _cluster/health?pretty: Der Status green bedeutet, alle Shards inklusive Replicas sind zugewiesen, yellow bedeutet, primäre Shards sind verfügbar, aber mindestens eine Replica fehlt, und red bedeutet, mindestens ein primärer Shard ist nicht erreichbar - in diesem Zustand liefert die Suche unvollständige oder gar keine Ergebnisse mehr. Ein dauerhaft gelber Cluster ist kein akuter Notfall, aber ein Warnsignal für fehlende Kapazität oder falsch verteilte Nodes.

GET _cat/indices?v&h=index,docs.count,store.size,pri,rep liefert auf einen Blick Dokumentanzahl, Speichergröße und Shard-Verteilung aller Indizes, ideal, um verwaiste Alt-Indizes nach fehlgeschlagenen Reindexierungen zu identifizieren. Das Slow Log protokolliert Queries, die einen konfigurierbaren Schwellenwert überschreiten, getrennt nach Query- und Fetch-Phase, und ist der zuverlässigste Weg, um wiederkehrende teure Query-Muster im Produktionsbetrieb zu identifizieren, statt sie erst durch Nutzerbeschwerden zu bemerken.

9. Query-Patterns im direkten Vergleich

Die folgenden Query-Muster tauchen in nahezu jedem Magento-Suchindex auf und unterscheiden sich in ihren tatsächlichen Ausführungskosten oft um Größenordnungen. Die Tabelle zeigt, welches Pattern in der Praxis performant bleibt und welches bei wachsendem Katalog zum Problem wird.

Bereich Empfohlenes Pattern (gut) Teures Pattern (Fehler) Empfohlene Optimierung
Präfix-Suche match auf edge_ngram-Feld wildcard: "*schuh*" Edge-N-Gram-Feld beim Indexieren anlegen
Ungenaue Eingaben fuzziness: "AUTO" fuzzy mit fixem Edit-Distance-Wert Fuzziness auf Suchfeld begrenzen
Attributfilter term/terms auf keyword-Feld wildcard auf analysiertem Textfeld Facettenattribute als keyword mappen
Sortierung nach Formel vorab berechnetes Sort-Feld script_score bei jeder Anfrage Wert beim Indexieren vorberechnen
Aggregationsgröße size begrenzt (z.B. 50) unbegrenzte terms-Aggregation size und shard_size gezielt tunen

Auffällig ist, dass fast jedes teure Pattern eine gleichwertige, aber index-basierte Alternative hat, der Trick besteht meist darin, Rechenaufwand von der Suchzeit in die Indexierungszeit zu verschieben, wo er nur einmal statt bei jeder Anfrage anfällt. Wer diese fünf Muster in seinem Katalog konsequent vermeidet, reduziert die durchschnittliche Query-Latenz oft um mehr als die Hälfte.

Mironsoft

Performance-Tuning, Elasticsearch/OpenSearch und Suchoptimierung für Magento-Shops

Elasticsearch- oder OpenSearch-Cluster professionell tunen?

Wir analysieren Index-Mapping, Shard-Verteilung, JVM-Heap und Query-Muster eures Magento-Suchclusters, identifizieren die konkreten Engpässe und setzen gezielte Optimierungen um, von Mapping-Korrekturen bis zur Slow-Log-basierten Query-Analyse.

Cluster-Health-Audit

Mapping-, Shard- und Heap-Analyse mit priorisiertem Maßnahmenplan

Query-Profiling

Explain- und Profile-API-Analyse teurer Layered-Navigation-Queries

Monitoring-Setup

Slow-Log-Konfiguration und Cluster-Health-Alerts in der Betriebsüberwachung

10. Zusammenfassung

Elasticsearch/OpenSearch Performance-Tuning für Magento löst ein wiederkehrendes Problem: langsame Facettensuche und Kategorieseiten trotz ausreichend dimensionierter Hardware. Ein sauberes Index-Mapping mit keyword-Feldern für Filterattribute reduziert die Datenmenge pro Query von Anfang an. Shard-Sizing zwischen 10 und 50 GB pro Shard vermeidet unnötigen Koordinationsaufwand, während ein JVM-Heap bei maximal 50 % des RAM und unterhalb der 32-GB-Compressed-OOPs-Grenze Garbage-Collection-Pausen kontrolliert hält.

Explain- und Profile-API liefern die Diagnosedaten, um teure Query-Muster wie führende Wildcards oder unbegrenzte Fuzzy-Suchen gezielt durch indexbasierte Alternativen wie Edge-N-Gram-Analyzer zu ersetzen. Kontinuierliches Monitoring über _cluster/health, _cat/indices und das Slow Log stellt sicher, dass Regressionen nach Reindexierungen oder Katalogwachstum frühzeitig auffallen, statt erst bei spürbaren Timeouts im Live-Betrieb.

Elasticsearch/OpenSearch Performance-Tuning - Das Wichtigste auf einen Blick

Mapping

keyword statt text für Facettenattribute, doc_values und index nur wo nötig aktivieren.

Shards & Heap

10-50 GB pro Shard, Heap max. 50 % RAM und unterhalb 32 GB wegen Compressed OOPs.

Query-Profiling

Explain- und Profile-API zur gezielten Diagnose, nie dauerhaft in Produktion aktiv.

Monitoring

_cluster/health, _cat/indices und Slow Log kontinuierlich beobachten.

11. FAQ: Elasticsearch/OpenSearch Performance-Tuning für Magento

1Warum ist keyword statt text für Filterattribute wichtig?
keyword speichert den exakten Wert ohne Analyzer-Overhead und ermöglicht schnelle term-Filter und Aggregationen. text ist für Volltextsuche gedacht und erzeugt bei Filterwerten unnötigen Rechenaufwand.
2Wie viele Shards braucht ein Magento-Katalog?
Meist 1 bis 3 primäre Shards pro Index bei Katalogen unter 5 Millionen Produkten, mit 10 bis 50 GB Zieldaten pro Shard. Mehr Shards erhöhen nur den Koordinationsaufwand.
3Wie groß sollte der JVM-Heap sein?
Maximal 50 % des verfügbaren RAM, niemals über etwa 30 bis 32 GB wegen des Compressed-OOPs-Verlusts. -Xms und -Xmx immer identisch setzen.
4Was zeigt die Explain API konkret?
Wie sich der Relevanz-Score einer Query für ein Dokument aus den einzelnen Klauseln zusammensetzt, ideal zum Debuggen unerwarteter Sortierung oder Boosting-Fehler.
5Warum sind Wildcard-Queries mit führendem Sternchen so teuer?
Sie können nicht über den invertierten Index aufgelöst werden und erzwingen einen Scan über alle Terms im Feld, was bei hoher Kardinalität zu linearer Suchzeit führt.
6Was bedeutet der Cluster-Status yellow?
Alle primären Shards sind verfügbar, aber mindestens eine Replica fehlt. Die Suche funktioniert, aber Ausfallsicherheit und Lesekapazität sind eingeschränkt.
7Wofür ist das Slow Log nützlich?
Es protokolliert Queries oberhalb eines Schwellenwerts getrennt nach Query- und Fetch-Phase und macht teure, wiederkehrende Query-Muster im Produktivbetrieb sichtbar.
8Was ist der Unterschied zwischen Elasticsearch und OpenSearch für Magento?
Magento unterstützt OpenSearch über den Elasticsearch-kompatiblen Adapter ab 2.4.x. Die API ist weitgehend identisch, Lizenzmodell und Feature-Entwicklung unterscheiden sich zunehmend.
9Wie oft sollte reindexiert werden und wirkt sich das auf die Performance aus?
Live-Reindexierung über den Standard-Indexer läuft inkrementell. Volle Reindexierungen außerhalb der Stoßzeiten mit erhöhter batch_size fahren, um Cluster-Last zu minimieren.
10Reicht ein einzelner Node für einen produktiven Magento-Shop?
Technisch ja für kleine Kataloge, aber ohne Replica-Shards keine Ausfallsicherheit. Ab mittlerer Größe mindestens ein Zwei- bis Drei-Node-Cluster mit Replicas empfehlenswert.