Faceted Navigation: Mapping-Design auf Aggregationen abstimmen
AI generated
_doc
_index
Elasticsearch · OpenSearch · Mapping · E-Commerce-Suche
Faceted Navigation: Mapping-Design auf Aggregationen abstimmen
warum das Attribut-Mapping über die Facetten-Performance entscheidet

Faceted Navigation lebt von Terms-Aggregationen auf Produktattributen, aber diese Aggregationen sind nur so schnell wie das darunterliegende Mapping. Wer Attribute als analysierten text-Typ statt als keyword indexiert, bekommt zerstückelte Filterwerte, doppelte Facetten und Aggregationen, die bei jeder Kategorieseite unnötig viel Speicher und Rechenzeit verbrauchen.

18 Min. Lesezeit keyword-Mapping · Terms-Aggregation · eager_global_ordinals Elasticsearch 8.x · OpenSearch 2.x

1. Warum Mapping die eigentliche Facetten-Stellschraube ist

Faceted Navigation, im Shop-Kontext oft Layered Navigation genannt, zeigt Kunden neben der Produktliste eine Reihe von Filtern mit Trefferzahlen: Marke, Farbe, Preisspanne, Material. Technisch entsteht jede dieser Facetten aus einer Terms- oder Range-Aggregation, die parallel zur eigentlichen Produktsuche über dieselbe Query läuft. Die Qualität dieser Faceted Navigation hängt aber nicht in erster Linie von der Aggregations-Syntax ab, sondern vom Mapping der zugrunde liegenden Attribute.

Ein falsch gewähltes Feld-Mapping macht sich nicht sofort bemerkbar. Die Query läuft, die Facette erscheint, aber die Werte sind zerstückelt: "Nike Air Max" wird bei einem analysierten text-Feld zu den zwei separaten Facetten-Werten "nike" und "air" und "max", statt als ein einziger Marken-Wert zu erscheinen. Dieses Muster ist der häufigste Grund, warum eine Faceted Navigation in der Praxis unbrauchbare Filterlisten produziert, obwohl die Aggregations-Query selbst syntaktisch korrekt ist.

Die folgenden Abschnitte zeigen, wie Mapping-Design und Aggregationen für eine performante Faceted Navigation zusammenspielen: von der Grundregel keyword statt text über Global Ordinals bis zu Range-Facetten für numerische Attribute wie den Preis. Jedes Beispiel nutzt reale Mapping- und Aggregations-Syntax aus dem E-Commerce-Kontext.

2. keyword statt text: die Grundregel für Facetten-Felder

Der wichtigste Mapping-Grundsatz für Faceted Navigation lautet: Jedes Attribut, das als Filter angeboten werden soll, muss als keyword gemappt sein, nicht als text. Ein text-Feld durchläuft beim Indexieren einen Analyzer, der den Wert in einzelne Tokens zerlegt, kleinschreibt und gegebenenfalls Stopwörter entfernt. Eine Terms-Aggregation auf einem solchen Feld bildet Facetten aus diesen Tokens, nicht aus dem ursprünglichen Attributwert, was bei mehrwortigen Markennamen oder Kategoriebezeichnungen zu granularen, für Kunden unbrauchbaren Filtern führt.

Ein keyword-Feld dagegen wird unverändert und ohne Analyse indexiert. "Nike Air Max" bleibt exakt "Nike Air Max" als ein einziger Aggregations-Bucket. Für Farbwerte, Größenangaben, Markennamen und ähnliche kategoriale Attribute ist keyword deshalb praktisch immer die richtige Wahl für das Facetten-Mapping, unabhängig davon, ob dasselbe Attribut zusätzlich in der Volltextsuche eine Rolle spielt.


PUT /products
{
  "mappings": {
    "properties": {
      "brand":        { "type": "keyword" },
      "color":        { "type": "keyword" },
      "size":         { "type": "keyword" },
      "material":     { "type": "keyword" },
      "price":        { "type": "scaled_float", "scaling_factor": 100 },
      "name": {
        "type": "text",
        "analyzer": "standard"
      }
    }
  }
}

3. doc_values und der Speicherunterbau von Terms-Aggregationen

Terms-Aggregationen greifen nicht auf den invertierten Index zu, sondern auf eine separate spaltenorientierte Datenstruktur namens doc_values. Diese Struktur wird für jedes indexierte Feld standardmäßig automatisch mitgeschrieben, außer sie wird explizit deaktiviert, und ist so organisiert, dass Elasticsearch für eine Aggregation direkt "für jedes Dokument, welchen Wert hat Feld X" abfragen kann, statt wie bei einer Textsuche "welche Dokumente enthalten Wert Y". Diese spaltenorientierte Organisation ist der eigentliche Grund, warum Terms-Aggregationen auf keyword-Feldern für Faceted Navigation so effizient sind.

Ein wichtiges Detail für das Mapping-Design: doc_values für ein Feld zu deaktivieren spart etwas Speicher auf der Platte, macht aber jede Aggregation auf diesem Feld unmöglich. Für Attribute, die ausschließlich für die Volltextsuche gebraucht werden und niemals als Facette dienen sollen, kann das eine sinnvolle Optimierung sein. Für jedes Attribut, das Teil der Faceted Navigation ist, müssen doc_values dagegen zwingend aktiv bleiben, was standardmäßig ohnehin der Fall ist.

4. Global Ordinals und eager_global_ordinals

Bei keyword-Feldern nutzt Elasticsearch für Terms-Aggregationen eine Optimierung namens Global Ordinals: Statt bei jeder Aggregation die vollständigen Textwerte zu vergleichen, wird jedem eindeutigen Wert im Segment eine numerische ID zugewiesen, und die Aggregation rechnet nur noch mit diesen IDs. Der Aufbau dieser Ordinal-Struktur passiert standardmäßig beim ersten Aggregations-Request nach einem Segment-Merge oder Refresh, was diese erste Anfrage spürbar langsamer macht als alle folgenden.

Für Faceted Navigation auf stark frequentierten Kategorieseiten ist dieser einmalige Aufbau-Overhead unerwünscht, weil er zufällig einzelne Nutzer mit langsamen Antwortzeiten trifft, sobald ein Refresh die Ordinals invalidiert hat. Der Parameter eager_global_ordinals im Mapping löst dieses Problem, indem er den Aufbau der Ordinal-Struktur direkt nach jedem Refresh im Hintergrund anstößt, statt auf die nächste Nutzeranfrage zu warten. Diese Einstellung kostet etwas zusätzliche Indexierungszeit, verschiebt den Aufbau-Overhead aber komplett aus dem Nutzerpfad heraus.


PUT /products/_mapping
{
  "properties": {
    "brand": {
      "type": "keyword",
      "eager_global_ordinals": true
    },
    "color": {
      "type": "keyword",
      "eager_global_ordinals": true
    }
  }
}

5. Multi-Fields: Suche und Facette im selben Attribut

Viele Attribute sollen gleichzeitig durchsuchbar und facettierbar sein, etwa der Produktname oder die Kategorie. Elasticsearch löst diesen Konflikt mit Multi-Fields: Das Hauptfeld wird als text für die Volltextsuche gemappt, während ein Sub-Feld unter dem Namen .keyword denselben Wert zusätzlich unanalysiert speichert. Aggregationen für Faceted Navigation greifen dann gezielt auf das Sub-Feld zu, während die Suche weiterhin über das analysierte Hauptfeld läuft.

Dieses Muster vermeidet doppelte Datenhaltung im Quell-Dokument, weil Elasticsearch beide Repräsentationen automatisch aus demselben Eingabewert ableitet. Wichtig ist, im Aggregations-Request konsequent den vollen Pfad mit .keyword-Suffix zu verwenden, sonst greift die Aggregation versehentlich auf das analysierte Textfeld zu und produziert wieder zerstückelte Facetten-Werte.


PUT /products/_mapping
{
  "properties": {
    "category_name": {
      "type": "text",
      "fields": {
        "keyword": { "type": "keyword" }
      }
    }
  }
}

GET /products/_search
{
  "size": 0,
  "aggs": {
    "categories": {
      "terms": { "field": "category_name.keyword", "size": 20 }
    }
  }
}

6. Numerische Attribute: Range-Facetten statt Terms

Für den Preis oder ähnliche kontinuierliche numerische Attribute ist eine Terms-Aggregation ungeeignet, weil jeder einzelne Preis potenziell einen eigenen Bucket bildet und daraus keine sinnvolle Filterliste entsteht. Für diese Fälle ist die range-Aggregation die richtige Wahl innerhalb einer Faceted Navigation, weil sie feste oder dynamisch berechnete Preisspannen als Buckets definiert, etwa "0 bis 50 Euro", "50 bis 100 Euro" und "über 100 Euro".

Das Mapping numerischer Facetten-Felder profitiert vom scaled_float-Typ statt float, weil scaled_float intern als Integer mit einem festen Skalierungsfaktor gespeichert wird und dadurch kompakter ist und weniger Rundungsprobleme bei Aggregationen erzeugt als binäre Gleitkommazahlen. Für Preisfelder ist ein scaling_factor von 100 üblich, um Centbeträge exakt abzubilden.


GET /products/_search
{
  "size": 0,
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 50 },
          { "from": 50, "to": 100 },
          { "from": 100, "to": 250 },
          { "from": 250 }
        ]
      }
    }
  }
}

7. Filter-Aggregationen für Facetten mit aktivem Filter

Ein häufiges Anforderungsmuster in der Faceted Navigation: Wenn ein Kunde bereits nach Farbe "Rot" filtert, sollen die anderen Facetten wie Marke weiterhin alle verfügbaren Optionen zeigen, während die Farb-Facette selbst weiterhin alle Farben inklusive Trefferzahl anzeigt, nicht nur "Rot". Diese Anforderung löst man mit einer post_filter-Kombination oder mit einer eigenen filter-Aggregation pro Facette, die den aktiven Filter dieser einen Facette gezielt ausnimmt, während alle anderen aktiven Filter weiterhin angewendet werden.

In der Praxis bewährt sich für diesen Fall eine Struktur mit einer globalen Aggregation als Wurzel, unter der für jede Facette eine filter-Aggregation alle Filter außer dem eigenen anwendet, gefolgt von der eigentlichen Terms- oder Range-Aggregation. Dieses Muster erlaubt in einer einzigen Query korrekte Multi-Select-Facetten, ohne für jede Facette eine separate Anfrage an den Cluster zu senden.

Attributtyp Falsches Mapping Empfohlenes Mapping Effekt
Marke, Farbe, Größe text mit Analyzer keyword Kein Zerbrechen mehrwortiger Werte
Suchbarer Name nur text, keine Facette möglich text mit .keyword Multi-Field Suche und Facette im selben Attribut
Preis Terms-Aggregation auf float range-Aggregation auf scaled_float Sinnvolle Preisspannen statt Einzelwerte
Vielgenutzte Facette Standard-Ordinals, verzögerter Aufbau eager_global_ordinals: true Aufbau-Overhead aus dem Nutzerpfad entfernt
Nur-Text-Attribut doc_values standardmäßig aktiv, kostet Speicher doc_values: false, falls keine Facette nötig Speicher sparen, wenn nie aggregiert wird

8. Kardinalität und Bucket-Größe im Griff behalten

Die size-Angabe einer Terms-Aggregation bestimmt, wie viele Facetten-Werte zurückkommen, hat aber direkten Einfluss auf die Genauigkeit bei verteilten Indizes mit mehreren Shards. Da jeder Shard seine Top-N-Werte unabhängig ermittelt und der koordinierende Knoten diese Teilergebnisse zusammenführt, können bei knapper size-Angabe Werte mit tatsächlich hoher Gesamthäufigkeit fälschlich fehlen, wenn sie auf einzelnen Shards nicht unter den lokalen Top-N lagen. Für kritische Faceted Navigation-Facetten wie Marke ist deshalb eine großzügigere size in Kombination mit dem Parameter shard_size sinnvoll, der explizit steuert, wie viele Kandidaten jeder Shard vor dem Merge liefert.

Attribute mit sehr hoher Kardinalität, etwa individuelle Artikelnummern oder Freitext-Tags, eignen sich grundsätzlich schlecht als Facette, weil eine Terms-Aggregation mit tausenden Buckets weder für Nutzer sinnvoll noch für den Cluster performant ist. Für solche Felder ist entweder eine Vorab-Kategorisierung in gröbere Gruppen oder der komplette Verzicht auf eine Facette die bessere Wahl, unabhängig vom gewählten Mapping.

9. Typische Fehler und Debugging

Der häufigste Fehler bei Faceted Navigation ist eine Terms-Aggregation direkt auf ein analysiertes text-Feld ohne .keyword-Suffix. Das Ergebnis sind Facetten-Werte, die wie einzelne Wörter aussehen statt wie vollständige Attributwerte, oft bereits an der Kleinschreibung erkennbar, da der Standard-Analyzer alle Werte lowercased. Ein zweiter häufiger Fehler ist ein fehlendes Reindex nach einer Mapping-Änderung: Ein bestehendes Feld nachträglich von text auf keyword umzustellen, wirkt sich nur auf neu indexierte Dokumente aus, bereits vorhandene Dokumente behalten ihr altes Mapping bis zum vollständigen Reindex.


// WRONG: aggregating directly on an analyzed text field
{
  "aggs": {
    "brands": { "terms": { "field": "brand_name" } }
  }
}
// Result: fragmented tokens like "nike", "air", "max" instead of one value

// RIGHT: aggregate on the keyword sub-field
{
  "aggs": {
    "brands": { "terms": { "field": "brand_name.keyword" } }
  }
}

// WRONG: mapping change without reindex, old documents keep old mapping
PUT /products/_mapping
{ "properties": { "brand_name": { "type": "keyword" } } }
// existing documents indexed before this change are unaffected

// RIGHT: mapping change followed by a full reindex
POST /_reindex
{
  "source": { "index": "products" },
  "dest": { "index": "products_v2" }
}

Mironsoft

Elasticsearch- und OpenSearch-Beratung für Suche, Analytics und Dashboards

Facettennavigation, die auch bei vielen Attributen performant bleibt?

Wir gestalten Attribut-Mapping und Aggregationen so, dass Faceted Navigation korrekte Filterwerte, saubere Trefferzahlen und schnelle Antwortzeiten liefert, von der Mapping-Analyse bis zur Multi-Select-Facette.

Mapping-Review

Prüfung bestehender Attribut-Mappings auf keyword- und Multi-Field-Fehler

Facetten-Umsetzung

Terms- und Range-Aggregationen für Layered Navigation im Shop

Performance-Tuning

eager_global_ordinals, shard_size und Reindex-Strategie für große Kataloge

10. Zusammenfassung

Eine performante Faceted Navigation entsteht nicht durch die Aggregations-Query allein, sondern durch das darunterliegende Mapping. keyword statt text ist die Grundregel für jedes filterbare Attribut, Multi-Fields lösen den Konflikt zwischen Suche und Facette im selben Feld, und range-Aggregationen auf scaled_float ersetzen Terms-Aggregationen für kontinuierliche numerische Werte wie den Preis.

eager_global_ordinals verschiebt den Aufbau-Overhead von Global Ordinals aus dem Nutzerpfad, shard_size sichert die Genauigkeit bei verteilten Indizes ab, und filter-Aggregationen ermöglichen korrekte Multi-Select-Facetten in einer einzigen Query. Wer diese Bausteine im Mapping von Anfang an berücksichtigt, spart sich spätere Reindex-Zyklen und liefert Kunden eine Facettennavigation mit korrekten, unzerstückelten Filterwerten.

Faceted Navigation und Mapping-Design, das Wichtigste auf einen Blick

Grundregel keyword

Jedes Filter-Attribut als keyword mappen, niemals als analysierten text-Typ, sonst zerbrechen Werte in Tokens.

Multi-Fields

.keyword Sub-Feld für Facetten, text-Hauptfeld für Volltextsuche, beide aus demselben Wert abgeleitet.

Numerische Facetten

range-Aggregation auf scaled_float statt Terms-Aggregation für Preis und ähnliche kontinuierliche Werte.

Performance

eager_global_ordinals für vielgenutzte Facetten, shard_size für Genauigkeit, doc_values gezielt deaktivieren.

11. FAQ: Faceted Navigation und Mapping-Design

1Warum keyword statt text für Facetten?
Ein text-Feld wird analysiert und in Tokens zerlegt. Facetten aus Tokens statt vollständigen Werten sind unbrauchbar.
2Suche und Facette im selben Attribut?
Multi-Field mit .keyword Sub-Feld für Aggregationen, text-Hauptfeld für die Suche, beide aus demselben Wert.
3Warum keine Terms-Aggregation für Preis?
Jeder Preis würde einen eigenen Bucket bilden. range-Aggregation mit festen Spannen ist die richtige Wahl.
4Was bewirkt eager_global_ordinals?
Baut die Ordinal-Struktur nach jedem Refresh im Hintergrund auf, verhindert langsame erste Nutzeranfragen.
5Was passiert bei doc_values: false?
Aggregationen auf diesem Feld sind dann nicht mehr möglich. Nur sinnvoll für Felder ohne Facetten-Anspruch.
6Warum fehlen manchmal Facetten-Werte?
Bei mehreren Shards kann ein Wert lokal knapp die Top-N verfehlen. shard_size erhöhen behebt das.
7Alle Optionen bei aktivem Filter zeigen?
Eine filter-Aggregation pro Facette, die den eigenen Filter ausnimmt, alle anderen aber anwendet.
8Reicht eine reine Mapping-Änderung?
Nein, ein vollständiger Reindex ist nötig, da bestehende Dokumente ihr altes Mapping behalten.
9Hohe Kardinalität als Facette geeignet?
Grundsätzlich nicht. Vorab-Kategorisierung in gröbere Gruppen ist meist die bessere Lösung.
10scaled_float statt float für Preis?
Kompakter und weniger Rundungsprobleme bei Aggregationen als binäre Gleitkommazahlen.