Stemmer, Stopwortlisten und ICU-Normalisierung pro Sprache
Der Standardanalyzer von Elasticsearch behandelt jede Sprache gleich und ignoriert damit Stammformen, Stopwoerter und Sonderzeichen, die fuer Deutsch, Franzoesisch oder Englisch jeweils vollstaendig unterschiedlich sind. Ein Custom Analyzer pro Sprache, kombiniert mit einer Per-Field-per-Language-Mapping-Strategie, macht aus einer generischen Volltextsuche eine Suche, die in jeder Shop-Sprache tatsaechlich die passenden Treffer liefert.
Inhaltsverzeichnis
- 1. Warum Standardanalyzer fuer mehrsprachige Shops nicht ausreichen
- 2. Aufbau eines Custom Analyzers: Tokenizer, Filter, Char-Filter
- 3. Sprachspezifische Stemmer richtig konfigurieren
- 4. Stopwortlisten pro Sprache verwalten
- 5. Per-Field-per-Language: die Mapping-Strategie
- 6. Synonyme pro Sprache pflegen
- 7. Umlaute, Diakritika und ICU-Normalisierung
- 8. Custom Analyzer mit der _analyze API testen
- 9. Sprachuebergreifende Suche zur Query-Zeit steuern
- 10. Zusammenfassung
- 11. FAQ
1. Warum Standardanalyzer fuer mehrsprachige Shops nicht ausreichen
Der standard-Analyzer von Elasticsearch tokenisiert Text nach Wortgrenzen, wandelt in Kleinbuchstaben um und entfernt keine sprachspezifischen Stoppwoerter. Fuer einen mehrsprachigen Shop bedeutet das, dass eine Suche nach "Schuhe" nicht automatisch Dokumente mit "Schuh" oder "Schuhen" findet, weil ohne Custom Analyzer keine Stammformreduktion stattfindet. Jede Sprache hat eigene grammatikalische Regeln, die ein universeller Analyzer nicht abbilden kann, ohne fuer jede Sprache Kompromisse einzugehen.
Das Problem verschaerft sich bei Sprachen mit reicher Morphologie wie Deutsch, wo ein einzelnes Substantiv je nach Fall, Numerus und Zusammensetzung viele Oberflaechenformen annehmen kann. Ohne einen Custom Analyzer mit deutschem Stemmer muesste ein Shop entweder jede Wortform explizit indexieren oder Nutzer dazu zwingen, exakt die im Produkttitel verwendete Form einzugeben, was die Trefferquote einer Produktsuche erheblich reduziert.
Ein weiterer Aspekt betrifft Stoppwoerter: Woerter wie "und", "der", "fuer" im Deutschen oder "the", "and", "for" im Englischen tragen kaum Bedeutung fuer die Relevanz einer Suche, blaehen aber ohne Filterung den invertierten Index unnoetig auf und verwaessern das Scoring. Ein sprachspezifischer Custom Analyzer entfernt genau die Stoppwoerter, die fuer die jeweilige Sprache tatsaechlich irrelevant sind, statt eine pauschale, oft unpassende Liste fuer alle Sprachen gleichzeitig zu verwenden.
2. Aufbau eines Custom Analyzers: Tokenizer, Filter, Char-Filter
Ein Custom Analyzer in Elasticsearch besteht aus drei Bausteinen, die in fester Reihenfolge durchlaufen werden: zuerst optionale char_filter, die den Rohtext vor der Tokenisierung transformieren, dann genau ein tokenizer, der den Text in einzelne Tokens zerlegt, und schliesslich eine Kette von filter, die jedes Token weiterverarbeiten, etwa durch Kleinschreibung, Stammformreduktion oder Entfernen von Stoppwoertern.
Diese Komponentenstruktur macht einen Custom Analyzer vollstaendig konfigurierbar: statt einen der vordefinierten Sprachanalyzer wie german oder french unveraendert zu uebernehmen, lassen sich einzelne Filterschritte gezielt austauschen oder ergaenzen, etwa um einen zusaetzlichen Synonym-Filter oder eine projektspezifische Normalisierung einzubauen.
PUT products_de
{
"settings": {
"analysis": {
"filter": {
"german_stop": {
"type": "stop",
"stopwords": "_german_"
},
"german_stemmer": {
"type": "stemmer",
"language": "light_german"
}
},
"analyzer": {
"german_custom": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase",
"german_normalization",
"german_stop",
"german_stemmer"
]
}
}
}
},
"mappings": {
"properties": {
"name": { "type": "text", "analyzer": "german_custom" }
}
}
}
Der Filter german_normalization vereinheitlicht Umlaute und das scharfe S in ihre Grundform, bevor german_stemmer die Stammform bildet. Diese Reihenfolge ist wichtig: eine Custom Analyzer-Kette, die zuerst stemmt und danach normalisiert, liefert oft andere und schlechtere Ergebnisse, weil der Stemmer auf noch nicht normalisierten Umlauten arbeitet.
3. Sprachspezifische Stemmer richtig konfigurieren
Stemmer reduzieren Woerter auf ihre Wortstammform, damit "laufen", "laeuft" und "gelaufen" bei der Suche als verwandt erkannt werden. Elasticsearch bietet fuer die meisten europaeischen Sprachen eingebaute Stemmer, wobei fuer Deutsch typischerweise zwischen german, dem klassischen Snowball-Stemmer, und light_german, einer weniger aggressiven Variante, gewaehlt wird. Der leichte Stemmer reduziert weniger stark, was Praezision bevorzugt, waehrend der klassische Stemmer aggressiver kuerzt und dadurch mehr Recall auf Kosten gelegentlicher Fehltreffer liefert.
Fuer Franzoesisch und Englisch gilt dasselbe Prinzip mit sprachspezifischen Eigenheiten: der franzoesische Stemmer muss mit Elisionen wie "l'" und Akzentzeichen umgehen, waehrend der englische Stemmer vor allem regelmaessige Plural- und Verbformen behandelt. Die Wahl des richtigen Stemmers innerhalb eines Custom Analyzers ist keine rein technische Entscheidung, sondern haengt vom Produktkatalog ab: bei technischen Fachbegriffen, deren exakte Schreibweise wichtig ist, lohnt sich oft ein leichterer Stemmer oder ein zusaetzliches Keyword-Feld ohne Stemming als Fallback fuer exakte Treffer.
PUT products_fr
{
"settings": {
"analysis": {
"filter": {
"french_elision": {
"type": "elision",
"articles_case": true,
"articles": ["l", "m", "t", "qu", "n", "s", "j", "d", "c", "jusqu", "quoiqu", "lorsqu", "puisqu"]
},
"french_stop": { "type": "stop", "stopwords": "_french_" },
"french_stemmer": { "type": "stemmer", "language": "light_french" }
},
"analyzer": {
"french_custom": {
"type": "custom",
"tokenizer": "standard",
"filter": ["french_elision", "lowercase", "french_stop", "french_stemmer"]
}
}
}
}
}
4. Stopwortlisten pro Sprache verwalten
Elasticsearch liefert vordefinierte Stoppwortlisten fuer die meisten Sprachen ueber Kuerzel wie _german_, _french_ oder _english_, die als Ausgangspunkt in jedem Custom Analyzer dienen. Diese Standardlisten decken die haeufigsten Funktionswoerter ab, sind aber selten optimal fuer einen konkreten Shop, dessen Suchverhalten sich vom allgemeinen Sprachgebrauch unterscheidet.
In der Praxis lohnt es sich, projektspezifische Stoppwortlisten zu pflegen, die entweder Standardwoerter ergaenzen oder gezielt entfernen. Ein B2B-Shop koennte zum Beispiel das Wort "Set" aus der Stoppwortliste entfernen, weil es in Produktnamen eine relevante Bedeutung traegt, waehrend ein allgemeines Wort wie "neu" bewusst als Stoppwort ergaenzt wird, weil es in fast jedem zweiten Produkttitel vorkommt und keine Unterscheidungskraft bietet. Diese Anpassung erfolgt ueber eine externe Datei, die vom Custom Analyzer referenziert wird.
PUT products_de
{
"settings": {
"analysis": {
"filter": {
"german_stop_custom": {
"type": "stop",
"stopwords_path": "analysis/stopwords_de_custom.txt"
}
},
"analyzer": {
"german_custom": {
"type": "custom",
"tokenizer": "standard",
"filter": ["lowercase", "german_normalization", "german_stop_custom", "german_stemmer"]
}
}
}
}
}
Die Datei stopwords_de_custom.txt liegt im config-Verzeichnis des Clusters und kann versioniert im Repository gepflegt werden. Aenderungen an der Stoppwortliste wirken erst nach einem _analyze-Cache-Reload beziehungsweise nach einem Reindexing der betroffenen Dokumente, da bereits indexierte Tokens nicht rueckwirkend angepasst werden.
5. Per-Field-per-Language: die Mapping-Strategie
Die zentrale Architekturentscheidung fuer mehrsprachige Shops ist, ob jede Sprache einen eigenen Index oder ein gemeinsamer Index mit sprachspezifischen Feldern verwendet. Die Per-Field-per-Language-Strategie legt fuer jede unterstuetzte Sprache ein eigenes Unterfeld an, etwa name.de, name.fr, name.en, jeweils mit dem passenden Custom Analyzer fuer diese Sprache, waehrend alle Sprachen im selben physischen Dokument und Index liegen.
PUT products
{
"settings": {
"analysis": {
"analyzer": {
"de_custom": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "german_normalization", "german_stop", "german_stemmer"] },
"fr_custom": { "type": "custom", "tokenizer": "standard", "filter": ["french_elision", "lowercase", "french_stop", "french_stemmer"] },
"en_custom": { "type": "custom", "tokenizer": "standard", "filter": ["lowercase", "english_stop", "english_stemmer"] }
}
}
},
"mappings": {
"properties": {
"name": {
"properties": {
"de": { "type": "text", "analyzer": "de_custom" },
"fr": { "type": "text", "analyzer": "fr_custom" },
"en": { "type": "text", "analyzer": "en_custom" }
}
}
}
}
}
Diese Struktur erlaubt es, in einer einzigen Query gezielt gegen das passende Sprachfeld zu suchen, ohne mehrere Indizes verwalten oder synchronisieren zu muessen. Der Nachteil gegenueber separaten Indizes pro Sprache ist eine etwas groessere Dokumentgroesse, weil jedes Dokument alle Sprachversionen mitfuehrt, was bei sehr grossen Katalogen mit vielen Sprachen relevant werden kann. Fuer die meisten mehrsprachigen Shops ueberwiegt jedoch die operative Einfachheit eines gemeinsamen Index deutlich, insbesondere weil Updates an einem Produkt nur einen einzigen Schreibvorgang erfordern statt eines pro Sprachindex.
6. Synonyme pro Sprache pflegen
Synonym-Filter erweitern einen Custom Analyzer um die Faehigkeit, unterschiedliche Begriffe fuer dasselbe Konzept zu vereinheitlichen, etwa "Sofa" und "Couch" im Deutschen. Weil Synonympaare sprachspezifisch sind und sich kaum sinnvoll uebersetzen lassen, muss jede Sprache ihre eigene Synonymliste erhalten, die eng mit dem Wortschatz und den Suchgewohnheiten der jeweiligen Zielgruppe abgestimmt ist.
Technisch wird der Synonym-Filter als weiterer Schritt in die Filterkette des sprachspezifischen Custom Analyzers eingefuegt, typischerweise nach der Kleinschreibung und vor dem Stemming, damit Synonyme auf normalisierten, aber noch nicht gestemmten Tokens greifen. Bei Aenderungen an der Synonymliste ist zu beachten, dass synonym-Filter zur Indexierungszeit nur fuer neu indexierte Dokumente wirken, waehrend ein synonym_graph-Filter zur Suchzeit angewendet auch ohne Reindexing sofort greift, allerdings mit anderen Performance-Charakteristiken bei komplexen Mehrwort-Synonymen.
| Filter-Typ | Sprachspezifisch | Wirkt bei Reindexing | Typischer Einsatz |
|---|---|---|---|
| stemmer | Ja, pro Sprache | Erforderlich nach Aenderung | Stammformreduktion |
| stop | Ja, pro Sprache | Erforderlich nach Aenderung | Funktionswoerter entfernen |
| synonym (index-time) | Ja, pro Sprache | Erforderlich nach Aenderung | Begriffe vereinheitlichen |
| synonym_graph (search-time) | Ja, pro Sprache | Nicht noetig, sofort aktiv | Haeufig geaenderte Synonymlisten |
| icu_folding | Sprachuebergreifend | Erforderlich nach Aenderung | Diakritika normalisieren |
7. Umlaute, Diakritika und ICU-Normalisierung
Fuer Sprachen mit Diakritika, etwa deutsche Umlaute, franzoesische Accents oder skandinavische Sonderzeichen, reicht der einfache asciifolding-Filter oft nicht aus, weil er alle Sonderzeichen unterschiedslos auf ihre ASCII-Grundform reduziert und dabei semantisch relevante Unterschiede verwischt. Das ICU-Analysis-Plugin bietet mit icu_folding eine sprachbewusstere Normalisierung, die zwischen Zeichen unterscheidet, die tatsaechlich aequivalent sind, und solchen, die eine eigene Bedeutung tragen.
Fuer einen deutschen Custom Analyzer ist meist der eingebaute german_normalization-Filter die praezisere Wahl, weil er speziell auf deutsche Umlautregeln zugeschnitten ist, etwa die Umwandlung von "ae" zu "a" nur in bestimmten Kontexten, waehrend icu_folding als generische, sprachuebergreifende Loesung fuer gemischte Kataloge mit vielen unterschiedlichen Alphabeten dient, etwa bei internationalen Marktplaetzen mit kyrillischen oder griechischen Produktnamen.
PUT products_intl
{
"settings": {
"analysis": {
"analyzer": {
"icu_custom": {
"type": "custom",
"tokenizer": "icu_tokenizer",
"filter": ["icu_folding", "lowercase"]
}
}
}
}
}
8. Custom Analyzer mit der _analyze API testen
Bevor ein Custom Analyzer produktiv geht, sollte er ueber die _analyze API gegen typische Suchbegriffe getestet werden. Der Endpunkt zeigt exakt, welche Tokens ein gegebener Text nach jedem Filterschritt erzeugt, und deckt sofort auf, ob ein Stemmer zu aggressiv kuerzt, eine Stoppwortliste ein relevantes Wort entfernt, oder ein Synonym nicht wie erwartet greift.
# Test how the german_custom analyzer tokenizes a search term
curl -s -X POST "https://es.mironsoft.de:9200/products_de/_analyze" \
-H "Content-Type: application/json" -d '{
"analyzer": "german_custom",
"text": "Laufschuhe fuer Damen"
}' | jq '.tokens[].token'
# Expected output roughly: lauf, schuh, dame
Ein systematischer Testansatz fuer jeden Custom Analyzer umfasst eine Liste realer Suchanfragen aus den Logs, die regelmaessig gegen neue Analyzer-Versionen laufen, bevor diese in Produktion gehen. So lassen sich Regressionen erkennen, etwa wenn eine Aenderung an der Stoppwortliste ploetzlich ein Wort entfernt, das fuer eine bestimmte Produktkategorie tatsaechlich relevant war.
Mironsoft
Mehrsprachige Suche, Analyzer-Tuning und Elasticsearch-Relevanz
Suche, die in jeder Shop-Sprache wirklich trifft?
Wir konfigurieren sprachspezifische Custom Analyzer fuer euren mehrsprachigen Shop, pflegen Stopwortlisten und Synonyme pro Sprache und testen jede Aenderung systematisch gegen echte Suchanfragen aus euren Logs.
Analyzer-Design
Sprachspezifische Custom Analyzer fuer euren Produktkatalog entwerfen
Relevanz-Tuning
Stopwortlisten, Synonyme und Stemmer auf euer Sortiment abstimmen
Testing-Setup
Regressionstests fuer Analyzer-Aenderungen gegen echte Suchanfragen einrichten
9. Sprachuebergreifende Suche zur Query-Zeit steuern
Auch mit einer sauberen Per-Field-per-Language-Struktur bleibt die Frage, wie eine Suchanfrage zur Laufzeit dem richtigen sprachspezifischen Custom Analyzer zugeordnet wird. Der uebliche Ansatz ist, die Nutzersprache aus dem Session-Kontext, der Store-View oder dem Accept-Language-Header zu ermitteln und die Query gezielt gegen das passende Sprachfeld zu richten, etwa name.de fuer deutschsprachige Nutzer.
Fuer Faelle, in denen die Nutzersprache unklar ist oder ein Nutzer bewusst in mehreren Sprachen gleichzeitig sucht, laesst sich eine multi_match-Query gegen alle Sprachfelder gleichzeitig richten, wobei jedes Feld weiterhin mit seinem eigenen Custom Analyzer analysiert wird. Das Boosting einzelner Sprachfelder, etwa eine hoehere Gewichtung fuer die Haupt-Store-Sprache, sorgt dafuer, dass Treffer in der bevorzugten Sprache vor Treffern in anderen Sprachen erscheinen, ohne diese vollstaendig auszuschliessen.
10. Zusammenfassung
Ein Custom Analyzer pro Sprache ist die Grundlage jeder praezisen mehrsprachigen Suche, weil Stemmer, Stoppwortlisten und Normalisierungsregeln zwischen Sprachen fundamental unterschiedlich funktionieren. Die Per-Field-per-Language-Strategie mit dedizierten Unterfeldern pro Sprache im selben Index kombiniert operative Einfachheit mit sprachlicher Praezision, waehrend die _analyze API jeden Analyzer vor dem produktiven Einsatz gegen reale Suchbegriffe testbar macht.
Wer Stopwortlisten und Synonyme konsequent pro Sprache pflegt statt eine pauschale Konfiguration fuer alle Sprachen zu verwenden, und ICU- oder sprachspezifische Normalisierungsfilter je nach Katalogstruktur bewusst waehlt, baut eine Suche, die in jeder unterstuetzten Sprache tatsaechlich die Ergebnisse liefert, die Nutzer erwarten, statt eine kompromissbehaftete Einheitsloesung fuer alle Sprachen gleichzeitig zu erzwingen.
Custom Analyzer fuer mehrsprachige Shops: Das Wichtigste auf einen Blick
Analyzer-Aufbau
char_filter, tokenizer und filter-Kette bilden gemeinsam den Custom Analyzer.
Stemmer und Stopwoerter
Beide muessen pro Sprache eigenstaendig konfiguriert und gepflegt werden.
Per-Field-per-Language
Ein Unterfeld pro Sprache im selben Index vereint Einfachheit und Praezision.
Testing mit _analyze
Jeder Analyzer sollte vor Produktivbetrieb gegen reale Suchbegriffe geprueft werden.