Mapping-Design-Grundlagen: den Elasticsearch-Index richtig planen
AI generated
_doc
_index
Elasticsearch · OpenSearch · Mapping · Datenmodellierung
Mapping-Design-Grundlagen
den Index richtig planen, bevor das erste Dokument landet

Ein Elasticsearch-Index ohne durchdachtes Mapping funktioniert am ersten Tag meist problemlos und wird ab dem ersten produktiven Suchproblem zur Baustelle. Wer Feldtypen, Unveraenderlichkeit und Analyzer-Zuordnung vor dem Indexieren klaert, spart sich spaeter aufwendiges Reindexing und inkonsistente Suchergebnisse.

18 Min. Lesezeit text · keyword · numeric · date · Mapping-Planung Elasticsearch 8.x · OpenSearch 2.x

1. Was Mapping ist und warum es die wichtigste Entscheidung ist

Das Mapping eines Elasticsearch-Index ist das Schema, das festlegt, wie jedes Feld eines Dokuments gespeichert, indexiert und durchsuchbar gemacht wird. Anders als bei einer klassischen SQL-Tabelle ist ein Elasticsearch-Index kein starres Raster aus Spalten, sondern ein JSON-Dokumentenspeicher, dessen Struktur trotzdem klare Typregeln braucht. Genau diese Regeln definiert das Mapping: Welches Feld ist Volltext, welches ein exakter Vergleichswert, welches eine Zahl, welches ein Datum. Ohne bewusste Planung entscheidet Elasticsearch diese Fragen selbst, und die automatische Entscheidung ist nicht immer die richtige fuer den tatsaechlichen Anwendungsfall.

Die Praxis zeigt immer wieder denselben Ablauf: Ein Team indexiert die ersten Testdaten, alles funktioniert, der Index geht in Produktion, und Wochen spaeter faellt auf, dass eine Preis-Aggregation nicht funktioniert oder eine Sortierung nach Produktname fehlschlaegt. Die Ursache liegt fast immer im Mapping, das beim ersten Dokument automatisch erzeugt wurde und nie bewusst ueberprueft worden ist. Dieser Artikel zeigt, welche Feldtypen es gibt, wie man sie richtig zuordnet und warum die Investition in ein durchdachtes Mapping sich schon nach der ersten produktiven Woche auszahlt.

2. Feldtypen im Ueberblick: text, keyword, numeric, date

Elasticsearch kennt eine ganze Reihe von Feldtypen, aber vier Kategorien decken den Grossteil der praktischen Faelle ab. Der Typ text ist fuer Volltextsuche gedacht: Der Wert wird durch einen Analyzer in einzelne Tokens zerlegt, sodass eine Suche nach einem Teilbegriff innerhalb eines laengeren Satzes funktioniert. Der Typ keyword speichert den Wert dagegen unveraendert als einen einzigen Token und eignet sich fuer exakte Vergleiche, Filter, Sortierung und Aggregation, etwa bei Status-Feldern, IDs oder Tags. Diese Unterscheidung ist der wichtigste Baustein jedes Mapping-Designs.

Numerische Typen wie long, integer, short, float und double ermoeglichen Bereichsabfragen, mathematische Aggregationen und effiziente Sortierung. Der Typ date speichert Zeitstempel intern als Millisekunden seit der Unix-Epoche und akzeptiert beim Indexieren verschiedene Formatstrings, die im Mapping explizit konfiguriert werden koennen. Ergaenzend gibt es boolean fuer Wahrheitswerte, object und nested fuer verschachtelte Strukturen sowie spezialisierte Typen wie geo_point fuer Koordinaten. Jede dieser Entscheidungen im Mapping hat direkte Auswirkung darauf, welche Queries spaeter moeglich sind.

Ein haeufiger Irrtum: Viele Entwickler denken, der Feldtyp sei nur eine Speicheroptimierung. Tatsaechlich bestimmt der Typ im Mapping aber auch, welche Query-Klauseln ueberhaupt funktionieren. Ein match-Query auf einem keyword-Feld liefert selten das gewuenschte Ergebnis, weil kein Analyzer die Tokens aufbereitet hat. Umgekehrt liefert eine term-Query auf einem text-Feld oft unerwartete Treffer, weil sie gegen die einzelnen, durch den Analyzer erzeugten Tokens vergleicht und nicht gegen den Originalwert.


PUT /products
{
  "mappings": {
    "properties": {
      "sku":          { "type": "keyword" },
      "name":         { "type": "text" },
      "description":  { "type": "text" },
      "price":        { "type": "double" },
      "stock_count":  { "type": "integer" },
      "created_at":   { "type": "date", "format": "strict_date_optional_time||epoch_millis" },
      "in_stock":     { "type": "boolean" },
      "brand":        { "type": "keyword" }
    }
  }
}

3. Warum text und keyword grundverschieden sind

Der Unterschied zwischen text und keyword ist der Punkt, an dem das Mapping-Design am haeufigsten falsch verstanden wird. Ein text-Feld durchlaeuft beim Indexieren einen Analyzer, der den Wert in Kleinbuchstaben umwandelt, Satzzeichen entfernt und den Text in einzelne Woerter zerlegt. Der Wert "Wireless Kopfhoerer Pro" wird so zu den Tokens "wireless", "kopfhoerer" und "pro", die einzeln durchsuchbar sind. Genau das macht Volltextsuche moeglich, macht das Feld aber ungeeignet fuer exakte Vergleiche oder Sortierung, weil der urspruengliche String nicht mehr in einer sortierbaren Form vorliegt.

Ein keyword-Feld hingegen speichert "Wireless Kopfhoerer Pro" als exakt diesen einen String, ohne Zerlegung. Eine Filterabfrage nach genau diesem Wert funktioniert zuverlaessig, eine Sortierung nach dem Feld liefert alphabetisch korrekte Ergebnisse, und eine Aggregation zaehlt jeden eindeutigen String separat. Wer versucht, auf einem text-Feld zu sortieren, erhaelt entweder einen Fehler oder muss auf ein zusaetzliches keyword-Sub-Feld ausweichen, das genau fuer diesen Zweck existiert.

4. Numeric- und Date-Typen richtig waehlen

Bei numerischen Feldern lohnt sich ein zweiter Blick auf die Groesse des gewaehlten Typs. Ein long-Feld belegt mehr Speicher als ein integer-Feld und ist fuer Werte wie eine Lagerbestandsmenge meist ueberdimensioniert. Bei grossen Indizes mit Millionen Dokumenten summiert sich dieser Unterschied spuerbar in Speicherverbrauch und Abfragegeschwindigkeit. Seit neueren Elasticsearch-Versionen gibt es zusaetzlich den Typ scaled_float, der Fliesskommawerte als skalierte Ganzzahl speichert und fuer Preise mit fester Nachkommastellenzahl effizienter ist als double.

Beim Typ date ist das Format-Attribut im Mapping entscheidend. Ohne explizites Format akzeptiert Elasticsearch mehrere Standardformate gleichzeitig, was zu inkonsistenten Werten fuehren kann, wenn verschiedene Datenquellen unterschiedliche Formate liefern. Ein explizit gesetztes Format wie strict_date_optional_time||epoch_millis im Mapping zwingt alle einlaufenden Werte in ein konsistentes Muster und verhindert, dass ein fehlerhaft formatierter Zeitstempel den gesamten Index-Request scheitern laesst oder unbemerkt falsch interpretiert wird.


# Inspect the current mapping of an existing index
curl -s -X GET "https://localhost:9200/products/_mapping?pretty" \
  -u elastic:changeme

# Check a single field's mapping only
curl -s -X GET "https://localhost:9200/products/_mapping/field/price?pretty" \
  -u elastic:changeme

5. Warum Mapping-Aenderungen im laufenden Betrieb so schwierig sind

Der zentrale Grund, weshalb Mapping-Design vor dem Indexieren stattfinden sollte, liegt in der internen Architektur von Elasticsearch: Ein bestehendes Feld kann nachtraeglich nicht mehr von einem Typ in einen anderen geaendert werden. Der Versuch, ein text-Feld nachtraeglich zu keyword zu aendern, scheitert mit einem klaren Fehler, weil die zugrunde liegende Lucene-Segmentstruktur bereits mit dem urspruenglichen Typ geschrieben wurde. Diese Unveraenderlichkeit ist keine Einschraenkung von Elasticsearch, sondern eine direkte Folge davon, wie invertierte Indizes physisch aufgebaut sind.

Was im Mapping nachtraeglich moeglich ist, sind additive Aenderungen: neue Felder koennen jederzeit hinzugefuegt werden, solange sie vorher nicht existierten. Auch bestimmte Parameter wie ignore_above bei keyword-Feldern lassen sich in manchen Faellen aktualisieren. Aber jede Aenderung, die den zugrunde liegenden Datentyp betrifft, erfordert zwingend einen neuen Index mit korrigiertem Mapping und einen anschliessenden Reindex-Vorgang. Das macht deutlich, warum die erste Mapping-Entscheidung so viel Gewicht hat: Ein Fehler hier ist kein Bugfix, sondern eine Datenmigration.

6. Explizites Mapping statt dynamischer Erkennung

Ohne explizite Definition erzeugt Elasticsearch beim ersten Dokument automatisch ein Mapping nach eigenen Heuristiken. Ein String-Wert wird typischerweise sowohl als text als auch als keyword-Sub-Feld angelegt, eine Zahl als long oder float, ein erkennbares Datumsformat als date. Diese automatische Erkennung funktioniert fuer einfache Faelle brauchbar, trifft aber regelmaessig Entscheidungen, die fuer den konkreten Anwendungsfall suboptimal sind, etwa wenn eine Produkt-ID als Zahl statt als keyword erkannt wird und dadurch fuehrende Nullen verloren gehen.

Der robuste Ansatz ist, das Mapping vor dem ersten Dokument explizit per PUT-Request zu definieren. Das kostet beim Index-Setup etwas mehr Zeit, verhindert aber genau die Ueberraschungen, die spaeter zu Reindexing-Aufwand fuehren. Ein gutes Vorgehen ist, mit ein paar realistischen Testdokumenten zu beginnen, das automatisch erzeugte Mapping per GET _mapping zu inspizieren, es als Ausgangspunkt zu nehmen und dann bewusst zu korrigieren, bevor der produktive Datenimport startet.

7. Index-Templates: Mapping fuer zukuenftige Indizes festlegen

Bei Anwendungsfaellen mit zeitbasierten Indizes, etwa taeglichen Log-Indizes, waere es unpraktisch, das Mapping jeden Tag manuell neu zu setzen. Hier kommen Index-Templates ins Spiel: Ein Template definiert ein Mapping, das automatisch auf jeden neu erstellten Index angewendet wird, dessen Name zu einem definierten Muster passt. So bekommt jeder Index mit dem Muster logs-app-* automatisch dasselbe Mapping, ohne dass ein Operator eingreifen muss.

Composable Index-Templates, seit Elasticsearch 7.8 verfuegbar, erlauben zusaetzlich, Mapping-Bausteine aus mehreren Component-Templates zusammenzusetzen. Eine gemeinsame Basis mit Standardfeldern wie @timestamp kann so mit anwendungsspezifischen Erweiterungen kombiniert werden, ohne Redundanz im Mapping. Das reduziert Copy-Paste-Fehler erheblich und macht Aenderungen an gemeinsamen Feldern an einer einzigen Stelle pflegbar.


PUT /_index_template/logs-app-template
{
  "index_patterns": ["logs-app-*"],
  "priority": 200,
  "template": {
    "settings": { "number_of_shards": 1, "number_of_replicas": 1 },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "level":      { "type": "keyword" },
        "message":    { "type": "text" },
        "service":    { "type": "keyword" },
        "trace_id":   { "type": "keyword" }
      }
    }
  }
}

8. Reindexing als Ausweg bei Fehlplanung

Wenn ein bestehendes Mapping doch korrigiert werden muss, fuehrt kein Weg an einem Reindex vorbei. Der Ablauf: Ein neuer Index mit korrigiertem Mapping wird angelegt, die Reindex-API kopiert alle Dokumente aus dem alten in den neuen Index, und ein Alias wird umgeschaltet, sodass die Anwendung ohne Ausfallzeit auf den neuen Index zeigt. Dieser Alias-Swap ist der entscheidende Kniff, der Reindexing in Produktion planbar macht, statt eine harte Downtime zu erzwingen.

Wichtig ist, den Reindex-Vorgang bei grossen Indizes nicht zu unterschaetzen: Bei mehreren hundert Millionen Dokumenten kann ein vollstaendiger Reindex Stunden dauern und signifikant Cluster-Ressourcen binden. Die Reindex-API unterstuetzt deshalb slices zur Parallelisierung und einen Parameter wait_for_completion=false, um den Vorgang asynchron im Hintergrund laufen zu lassen und den Fortschritt separat abzufragen. Wer von Anfang an sauberes Mapping-Design betreibt, reduziert die Haeufigkeit, mit der ein solcher aufwendiger Vorgang ueberhaupt noetig wird.


POST /_reindex?wait_for_completion=false
{
  "source": { "index": "products_v1" },
  "dest":   { "index": "products_v2" },
  "conflicts": "proceed"
}

GET /_tasks/<task_id>

POST /_aliases
{
  "actions": [
    { "remove": { "index": "products_v1", "alias": "products" } },
    { "add":    { "index": "products_v2", "alias": "products" } }
  ]
}

9. Mapping-Design in der Praxis: ein vollstaendiges Beispiel

Ein realistisches Beispiel macht die Prinzipien greifbar. Ein Produktkatalog fuer einen Onlineshop braucht mindestens folgende Feldkategorien im Mapping: eine eindeutige, exakt vergleichbare SKU als keyword, einen durchsuchbaren Produktnamen als text mit einem zusaetzlichen keyword-Sub-Feld fuer Sortierung, einen Preis als double oder scaled_float, einen Lagerbestand als integer und ein Erstellungsdatum als date mit explizitem Format. Genau dieses Zusammenspiel zeigt, dass gutes Mapping-Design kein einzelner Trick ist, sondern die konsequente Anwendung mehrerer kleiner Entscheidungen.

Vor dem produktiven Rollout lohnt sich ein Testlauf: Ein paar hundert reale Beispieldokumente in einen Testindex laden, alle geplanten Queries gegen dieses Mapping ausprobieren, insbesondere Sortierungen, Aggregationen und Bereichsfilter, und erst danach den finalen Index fuer den produktiven Import anlegen. Dieser Testlauf kostet eine Stunde und spart im Zweifel Tage an spaeterem Reindexing, wenn ein Feldtyp sich als falsch herausstellt.

Fuer Magento-Betreiber, die den integrierten Elasticsearch-Katalogindex nutzen, gilt dasselbe Prinzip auf einer anderen Ebene: Custom-Attribute, die per searchable- und filterable-Flag im Produktattribut konfiguriert werden, wirken sich direkt auf das generierte Mapping des Katalogindex aus. Ein Attribut, das faelschlich als durchsuchbarer Text statt als Filterwert markiert wird, erzeugt dieselben Probleme wie ein falsch geplantes Mapping in einem eigenen Index, nur verborgen hinter der Magento-Abstraktionsschicht.

Feldtyp Verwendungszweck Sortierbar / Aggregierbar Typisches Beispiel
text Volltextsuche, analysierte Tokens nur mit keyword-Sub-Feld Produktbeschreibung, Blogtext
keyword Exakte Vergleiche, Filter, Tags ja, direkt SKU, Status, Kategorie-ID
long / integer Ganzzahlen, Zaehler, IDs ja, direkt Lagerbestand, Bestellnummer
double / scaled_float Fliesskommawerte, Preise ja, direkt Preis, Bewertungs-Score
date Zeitstempel mit festem Format ja, direkt created_at, Bestelldatum

Diese Tabelle ersetzt keine vollstaendige Mapping-Dokumentation, zeigt aber die Grundregel: Sobald Sortierung oder Aggregation gebraucht wird, ist ein exakter Feldtyp wie keyword, ein numerischer Typ oder date notwendig. Volltextsuche gehoert immer zu text, niemals zu einem der exakten Typen. Wer diese Grundregel beim Mapping-Design befolgt, vermeidet die meisten der spaeter beobachteten Query-Fehler.

10. Zusammenfassung

Gutes Mapping-Design beginnt nicht beim ersten Query, sondern beim ersten Dokument. Die Feldtypen text, keyword, numerische Typen und date decken die meisten Anwendungsfaelle ab, muessen aber bewusst gewaehlt werden, weil die dynamische Erkennung von Elasticsearch nicht immer die passende Entscheidung trifft. Die Unveraenderlichkeit bestehender Feldtypen macht jede spaetere Korrektur zu einem Reindex-Vorgang, weshalb Planung vor dem produktiven Import den groessten Hebel darstellt.

Index-Templates automatisieren konsistentes Mapping ueber viele Indizes hinweg, waehrend die Reindex-API mit Alias-Swap eine planbare Ausweichroute bietet, wenn eine Korrektur trotzdem noetig wird. Wer diese Bausteine kennt und ein Mapping vor dem ersten Datenimport bewusst entwirft, vermeidet den typischen Kreislauf aus Testindex, Ueberraschung und Notfall-Reindex, der in vielen Projekten unnoetig Zeit kostet.

Mapping-Design-Grundlagen, das Wichtigste auf einen Blick

text vs. keyword

text fuer Volltextsuche mit Analyzer, keyword fuer exakte Vergleiche, Filter, Sortierung und Aggregation. Nie verwechseln.

Unveraenderlichkeit

Ein bestehender Feldtyp im Mapping laesst sich nicht aendern, nur neue Felder koennen ergaenzt werden. Fehler erfordern Reindexing.

Explizites Mapping

Vor dem ersten produktiven Dokument per PUT definieren, statt der dynamischen Erkennung von Elasticsearch zu vertrauen.

Index-Templates

Bei zeitbasierten Indizes automatisch konsistentes Mapping anwenden, statt es manuell pro Index zu wiederholen.

11. FAQ: Mapping-Design-Grundlagen

1Was ist der Unterschied zwischen Mapping und Schema?
Mapping ist der Elasticsearch-Begriff fuer das Index-Schema: es definiert pro Feld den Datentyp und die Indexierung, aehnlich einer Tabellendefinition, aber flexibler.
2Kann ich text zu keyword aendern?
Nein, bestehende Feldtypen sind unveraenderlich. Nur ein neuer Index mit korrigiertem Mapping plus Reindex loest das Problem.
3Wie sehe ich das aktuelle Mapping?
GET /index_name/_mapping liefert das vollstaendige Mapping, GET /index_name/_mapping/field/feldname nur ein einzelnes Feld.
4Was passiert ohne explizites Mapping?
Elasticsearch erzeugt automatisch ein Mapping per Dynamic Mapping. Funktioniert fuer einfache Faelle, trifft aber nicht immer die optimale Typwahl.
5long oder integer verwenden?
Nur bei Werten ausserhalb des Integer-Bereichs long nutzen. Fuer die meisten Zaehler und IDs reicht integer und spart Speicher.
6Wann brauche ich ein Index-Template?
Bei zeitbasierten Indizes wie taeglichen Log-Indizes, damit jeder neue Index automatisch dasselbe Mapping erhaelt.
7Wie lange dauert ein Reindex?
Abhaengig von Dokumentanzahl und Clustergroesse, bei sehr grossen Indizes durchaus Stunden. Der Parameter slices parallelisiert und verkuerzt die Laufzeit.
8Ist der alte Index waehrend Reindex nutzbar?
Ja, der alte Index bleibt lesbar. Erst nach Abschluss schaltet ein Alias-Swap ohne Downtime auf den neuen Index um.
9Was ist scaled_float?
Speichert Fliesskommawerte als skalierte Ganzzahl, etwa Preise als Cent-Betrag. Spart Speicher gegenueber double bei fester Nachkommastellenzahl.
10Betrifft das auch Magento-Kataloge?
Ja, der Magento-Katalogindex generiert sein Mapping aus searchable- und filterable-Flags der Attribute. Falsche Konfiguration erzeugt dieselben Probleme.