Zur Übersicht

Suchen und Finden im Web – Elasticsearch für Fortgeschrittene

Sabine Bär
Sabine Bär Aktualisiert am 17. Aug. 2020
Suchen und Finden mit Elasticsearch: Mapping, Analyzer und Tokenizer

Wer im Web sucht, der soll auch etwas finden. Dafür bietet Elasticsearch die besten Voraussetzungen. Wie du Mapping, Analyzer und Tokenizer richtig einsetzt, dass erfährst du hier.

Du hast den ersten Teil meiner Blogreihe verpasst? Dann geht es für dich hier entlang:  Einführung in Elasticsearch

Das Mapping

Prinzipiell kann Elasticsearch ohne Schemas arbeiten – das heißt, du musst kein explizites Mapping definieren. In diesem Fall leitet Elasticsearch beim Indizieren eines Dokumentes den Datentyp vom Inhalt ab. Du kannst während des Betriebs einfach neue Felder hinzufügen, indem du ein Dokument indizierst, das dieses Feld enthält.

Meistens wird das Mapping aber expliziert definiert. Dadurch können dem Suchserver Informationen zu den Daten gegeben werden – und darüber, ob und wie sie durchsucht werden sollen. Für jede Spalte in einem Eintrag im Suchindex solltest du zumindest den Namen und den Datentyp definieren. Der Datentyp kann entweder ein einfaches Feld sein – zum Beispiel ein String oder ein Boolean – oder ein verschachteltes, das wieder ganze Objekte enthalten kann.

Elasticsearch kann sehr gut mit verschachtelten Objekten umgehen. Es gilt wieder das Prinzip des dynamischen Mappings: Ein verschachteltes Feld kann entweder einfach als „object“ definiert werden oder es kann wieder ein explizites Mapping für den verschachtelten Inhalt definiert werden.

Wir stellen uns als Beispiel einen Suchindex vor, der die Grundlage für eine Volltextsuche für Seiten einer Webseite sein soll. Eine Seite hat einen Titel, einen Inhalt, mehrere Tags und ist einer Sprache zugeordnet. Das Mapping könnte in diesem Fall folgendermaßen aussehen:

{
"my-index": {
    "mappings": {
      "my-document": {
        "properties": {
          "content": {"type": "string"},
          "language": {"type": "string"},
          "tags": {"type": "string"},
          "title": {"type": "string"},
          "uri": {"type": "string"}
        }
      }
    }
  }
}

Jeder Eintrag braucht eine ID. Wenn du sie nicht explizit angibst, wird sie von Elasticsearch generiert. Die URI brauchen wir als Referenz zu den Originaldaten, damit wir zum Beispiel in der Suchergebnisliste auf die Seite verlinken können. Die Sprache, der Titel und der Inhalt sind einfache Textfelder. Tags sind auch Strings, allerdings können das mehrere sein – Elasticsearch erkennt das automatisch.

Neben dem Datentyp kannst du pro Feld auch noch eine Reihe von Index-Optionen definieren. Generell muss angegeben werden, ob das Feld überhaupt durchsuchbar sein soll und ob es analysiert werden soll oder nicht.

Das Feld „uri“ aus dem vorigen Beispiel wollen wir zum Beispiel nicht durchsuchen. Wir brauchen es nur als Referenz zu den Originaldaten. Das Feld „language“ wollen wir eventuell durchsuchen (zum Beispiel wenn wir die Suchergebnisse nach Sprache filtern wollen). Es soll aber nicht analysiert werden, weil wir es nicht für eine Volltextsuche verwenden wollen. Auf die Felder „title“ und „content“ wollen wir eine Volltextsuche absetzen, darum definieren wir einen Analyzer dafür. Unser Beispiel von vorher sieht dann so aus:

{
"my-index": {
    "mappings": {
      "my-document": {
        "properties": {
          "content": {"type": "string","analyzer": "my-analyzer"},
          "language": {"type": "string","index": "not_analyzed"},
          "tags": {"type": "string","analyzer": "my-analyzer"},
          "title": {"type": "string","analyzer": "my-analyzer"},
          "uri": {"type": "string","index": "no"}
        }
      }
    }
  }
}

Tokenizer und Analyzer

Ich gebe der Suche ein Wort und bekomme dafür alle Einträge, die dieses Wort enthalten. Hört sich einfach an, sieht in der Praxis aber ganz anders aus. Tippfehler, Wortteile, Satzzeichen, Sonderzeichen – dem allem soll die Suche gewachsen sein. Dabei und auch bei der gewünschten Priorisierung der Suchergebnisse helfen uns Analyzer und Tokenizer.

Sogenannte Analyzer sind vor allem für die Volltextsuche wichtig. Ein Analyzer besteht aus einem Tokenizer und einem oder mehreren Token Filter. Der Tokenizer splittet den Inhalt in Tokens auf, die Filter führen zusätzlich noch Operationen auf diesen Token durch.

Es gibt viele Arten von Tokenizern, einer der bekannteren ist der NGram-Tokenizer. Dieser teilt den Inhalt in kleine Tokens und ermöglicht so eine intelligente Suche nach Wortteilen. Für einen NGram-Tokenizer mit einer Mindestlänge von drei und einer Maximallänge von 30 Zeichen würde man für den Text „Elasticsearch ist super.“ 73 Tokens ablegen. Allein für das Wort „super“ werden sechs davon erzeugt: sup, supe, super, upe, uper, per.

Der my-analzyer von unserem Mapping-Beispiel könnte folgendermaßen aussehen – wenn wir den oben beschriebenen Tokenizer verwenden wollen:

"analysis": {
    "analyzer": {
        "my-analyzer": {
            "filter": "lowercase",
            "tokenizer": "my-ngram-tokenizer"
        }
    },
    "tokenizer": {
        "my-ngram-tokenizer": {
            "max_gram": "30",
            "min_gram": "3",
            "type": "nGram",
            "token_chars": ["letter","digit"]
        }
    }
}

Anwendungsgebiete

Suchfunktionen sind natürlich in allen Themengebieten interessant. Besonders wichtig sind sie aber in Bereichen, in denen der Benutzer vorwiegend die Suche verwendet und zum Beispiel nicht über eine Navigation zu seinem Ziel kommt. Das sind unter anderem große Shopsysteme oder andere E-Commerce-Plattformen.

Aufgrund ihrer Geschwindigkeit kannst du Elasticsearch auch verwenden, um Daten schnell an ein anderes System auszuliefern. Zum Beispiel ein System, das wiederum einem anderen System Daten zur Verfügung stellt. Anstatt einen klassischen Weg zu nutzen – beispielsweise einen SOAP-Webservice – könnten die Daten vom einen System in den Suchindex geschrieben und vom anderen System direkt aus dem Suchindex gelesen werden.

Mein Fazit

Wer suchet, der soll auf jeden Fall etwas finden. Elasticsearch bietet die besten Voraussetzungen dafür – schnell, flexibel und skalierbar. Auch wenn der Weg zur perfekten Konfiguration nicht immer der kürzeste ist, das Ergebnis wird deine Besucher auf jeden Fall überzeugen.

(Bildquelle: davide ragusa/unsplash.com)

Sabine Bär
Sabine Bär
Director of Development
Sabine ist Web Developerin bei MASSIVE ART. Wäldar ka nüd jedar sin, Web-Entwicklerin auch nicht. Sabine ist beides aus Leidenschaft. Die Frau mit Hang zu komplexen Coding-Projekten hat ihre Prozesse, Zahlen und die Dev-Jungs voll im Griff.