Elasticsearch wurde 2010 als Open-Source-Projekt mit dem Ziel veröffentlicht, Datenzugriffe zu erleichtern. Heute ist es das Werkzeug der Wahl für extrem schnelle und skalierbare Suchen sowie Echtzeitanalysen von großen Datenmengen.

Elasticsearch wird besonders häufig für die Umsetzung von Webshops, wie zum Beispiel eBay, oder anderen Suchmaschinen verwendet. Uber nutzt Elasticsearch, um schnell große Mengen an Live-Daten verarbeiten zu können, während GitHub es einsetzt, um eine schnelle Suche durch Repositories, Nutzer oder Code-Segmente anbieten zu können.

Bei dem Grundbaustein Elasticsearch handelt es sich um eine verteilte, auf JSON basierende Suchmaschine. Alle Daten werden in diesem Format verarbeitet, gespeichert und abgefragt. Angebunden wird die Datenbank über eine einfache RESTful API. Mittlerweile wurde der Elastic-Stack um viele weitere Open-Source-Tools erweitert, die sich um die Sicherheit und Verarbeitungsprozesse dieser Daten kümmern. Auch gefragte Themen wie z.B. KI-Suchfunktionen sind nun verfügbar.

Kibana ermöglicht es dabei, die Elastic-Daten zu visualisieren und zu analysieren. Viele Funktionen sind kostenlos verfügbar, wie die Nutzung des Dashboards und die API-Schlüssel-Verwaltung. In den höheren Preisstufen enthält das Feature-Paket auch Machine-Learning-Komponenten, die sich z.B. für Trendanalysen eignen. Eine Übersicht darüber, welche Features für Elasticsearch und Kibana kostenfrei sind, befindet sich auf der Abonnement-Seite.

In diesem Artikel werden die Grundlagen für ein lokales Setup von Elasticsearch gelegt und ein Verständnis für Konfiguration, Datentypen und den dynamischen Generierungen geschaffen.

Terminologie

Elasticsearch ist eine NoSQL-Datenbank. Diese unterscheiden sich von klassischen relationalen Datenbanken, denn es wird nicht mit Tabellen und festgelegten Strukturen gearbeitet. Durch die Flexibilität innerhalb der Datenstruktur können auch unstrukturierte Daten, wie zum Beispiel Bilder oder ganze Texte, gespeichert werden.

Zum besseren Verständnis der nachfolgenden Begrifflichkeiten hilft es, diese für relationale und NOSQL-Datenbanken gegenüberzustellen.

Relationale Datenbank NoSQL Datenbank
Table, Tables Index, Indices
Schema Mapping
Row (Datensatz) Document
Column Field

Elasticsearch lokal starten

Docker Container starten

Zunächst wird in der Konsole mit Hilfe von Docker-Containern Schritt für Schritt eine Elasticsearch-Instanz aufgesetzt. Dazu wird zuerst auf der Konsole das Passwort für den Elastic User als Umgebungsvariable erstellt.

Wenn für das lokale Setup Kibana verwendet werden soll, ist es am Besten, direkt auch ein Netzwerk zu erstellen:

Beim Starten des eigentlichen Docker-Containers kann nun der Port (:9200) sowie das erstellte Passwort und das angelegte Netzwerk angegeben werden.

Kibana starten

Um eine verknüpfte Kibana-Instanz zu starten, wird auch hier zuerst in den Umgebungsvariablen ein Passwort gesetzt.

Die laufende Elasticsearch-Instanz kann nun mit dem erzeugten Kibana-Passwort konfiguriert werden.

Kibana kann jetzt gestartet werden. Auch hier wird der Port (:5601) definiert, sowie das erstellte Passwort und Netzwerk angegeben. Zusätzlich wird der Verweis auf die Elasticsearch-Instanz konfiguriert. Falls der Port geändert wurde, ist es wichtig, ihn dieser Stelle entsprechend anzupassen.

Nachdem die Instanz erfolgreich gestartet wurde, ist die Kibana-Oberfläche erreichbar.

Im favorisierten Browser kann diese unter localhost:5601 aufgerufen werden. Im nächsten Schritt erfolgt der Login mit den angelegten Benutzerinformationen.


Große Auswahl an günstigen Domain-Endungen – schon ab 0,08 € /Monat
Jetzt Domain-Check starten

API Key erstellen

Die Kibana-Oberfläche erlaubt es, viele Konfigurationen bequem vorzunehmen. Im Nachfolgenden wird die Erstellung und Konfiguration der Rechte mittels Kibana veranschaulicht.

Eine Anleitung für das Erstellen des API Keys ohne Kibana befindet sich hier.

Unter dem Punkt Getting Started/Elasticsearch befindet sich eine Anleitung zur Erstellung eines API Keys.

Lokal ist diese erreichbar unter:

http://localhost:5601/app/enterprise_search/elasticsearch

Die Anleitung enthält Code-Segmente für curl, Python, JavaScript, PHP, Go und Ruby. Aber auch die Option, den API Key über die Kibana-Oberfläche zu erstellen.

So muss der API Key nur noch benannt werden. Der erstellte Key sollte sicher abgelegt werden, da er später nicht mehr angezeigt werden kann. Wenn er verloren gehen sollte, ist es am sichersten, den vorherigen zu löschen und einen neuen zu erstellen.

Einfachheitshalber sollte in den Einstellungen (Manage API Key) das Prüfen der Sicherheitsprivilegien ausgestellt werden. Dadurch ist es möglich, mit Hilfe des API Keys auch gesicherte Aufrufe auszuführen, z.B. das Erstellen oder Löschen eines Index.

Postman Setup

Alle weiteren Aufrufe gegen die Elasticsearch-Instanz werden mittels API-Plattform Postman ausgeführt.

Wenn eigene Aufrufe erstellt werden oder weiter mit curl gearbeitet wird, ist es wichtig, bei den Aufrufen den API Key im Header mit anzugeben.

Beispiel: Konfiguration der Autorisierung des API Keys in Postman.

Request mit Kibana abschicken

Mit den Kibana Dev Tools können Requests direkt an Elasticsearch gesendet werden. Die Seite kann über die Seitenleiste unter dem Punkt Management aufgerufen werden. Alternativ kann im Browser der entsprechende Kibana-Link aufgerufen werden. Bei der lokalen Instanz ist die URL wie folgt:

http://localhost:5601/app/dev_tools#/console

Abbildung: Request mit Kibana abschicken

Die Requests können ganz normal geschrieben werden. Im Aufruf muss nur der Pfad angegeben werden.

Es können beliebig viele Requests in dem Dokument angelegt werden. Neben dem erstellten Request erscheint beim Hovern ein Play-Button. Um einen Aufruf auszuführen, muss der Cursor in der ersten Zeile des Requests sein und Play gedrückt werden. Die Antwort auf den Request erscheint dann auf der rechten Seite.

Um die Code-Beispiele einfach zu halten, werden alle nachfolgenden Beispiele als Kibana-Requests geschrieben. Wenn Sie dem Tutorial Schritt für Schritt folgen wollen, können Sie diese Requests einfach in die Kibana Dev Tools kopieren.

Eine simple Abfrage der Elastic-Version sieht in Kibana wie folgt aus:

Links der ausgeführte Request, rechts erscheint dann nach der Ausführung die Antwort.

Es können beliebig viele Requests hinterlegt werden, es wird jedoch immer nur die Antwort des letzten Requests angezeigt.

Die Kibana Dev Tools erlauben es auch, curl-Requests einzufügen, die automatisch der Kibana-Schreibweise angepasst werden.

Abbildung: Curl-Requests

Erstellen eines Index

Vor dem Erstellen des ersten Index sollte der Anwendungsfall kurz gedanklich skizziert werden. Für eine Testinstanz ist die Konfiguration grundsätzlich unerheblich. Werden die Einstellungen allerdings unüberlegt angegeben, kann es passieren, dass der Health Check des Clusters nicht im grünen Bereich landen kann.

Wenn es sich um eine produktiv genutzte Instanz handelt, sollte das Konzept von Shards und Replicas unbedingt verstanden werden.

Shards & Replicas

Shards sind eine einzelne Einheit eines Index. Elasticsearch verteilt unter allen bestehenden Shards eine Teilmenge der Daten. Dadurch können Daten auf mehrere Maschinen aufgeteilt werden. Das ist insbesondere dann relevant, wenn es sich um extrem große Datenmengen handelt.

Wenn ein neuer Index angelegt wird, wird entweder die angegebene Anzahl von Shards oder die Default-Konfiguration verwendet. In neueren Elastic-Versionen bedeutet das eine number_of_shards von 1. In älteren Versionen ist der Default 5.

Falls wirklich mit einer älteren Version gearbeitet wird, sollten die Shards explizit auf 1 gesetzt werden. Sonst kann der Status des Clusters in den roten Bereich fallen. Beim Starten einer Elasticsearch-Instanz versucht diese, ein existierendes Cluster zu finden. Wird keins gefunden, erstellt die Instanz ein neues Cluster. In diesem wird dann die angegebene Anzahl an Shards verteilt.

Ein Dokument (Datensatz) wird immer in einen Primary-Shard geschrieben. Daher muss es in jedem Index mindestens einen geben.

Elasticsearch migriert automatisch die Daten zwischen verschiedenen Shards, sodass alle Instanzen im Cluster ausbalanciert sind. Die Anzahl der Primary-Shards kann nach dem Erstellen des Index nicht aktualisiert werden. Daher legt die Anzahl der Shards implizit die maximale Datenmenge fest.

Zusätzlich zu den Primary-Shards können die Replicas konfiguriert werden. Das Erzeugen von mehreren Shards und Replicas ist erst lohnenswert, wenn mehrere Elastic-Instanzen gestartet werden. In einem Replica befindet sich eine Datenkopie eines Primary-Shards. Deshalb kann es sich nie auf derselben Instanz wie das kopierte Primary-Shard befinden.

Wenn eine Elastic-Instanz ausfällt, werden die Replicas auf der noch laufenden Instanz automatisch zu den neuen Primary-Shards. Wenn alle Instanzen wieder erreichbar sind, kümmert sich Elastic automatisch darum, die Shards wieder zu verteilen. Danach müssen die Daten der ausgefallenen Shards synchronisiert werden.

Zur Veranschaulichung hier ein Beispiel mit fünf Primary-Shards und einem Replica, also einer Kopie von jedem Shard, verteilt auf zwei Instanzen:

Abbildung: Beispiel mit fünf Primary-Shards

Der eingangs erwähnte Cluster-Status wird gelb, wenn mehr Replicas angegeben werden, als tatsächlich verteilt werden können. In der Schlussfolgerung kann bei nur einer Instanz also kein Replica verwendet werden, da diese nicht auf derselben Instanz wie die Primary-Shards laufen können. Dadurch meldet Elasticsearch unverteilte Replica Shards, und der Status wird gelb. Sollte der Fall eintreffen, dass es Primary-Shards gibt, die nicht verteilt werden können, dann wird dieser Status rot.

Die Anzahl der Replicas kann nach dem Erstellen des Index geändert werden, die Anzahl der Primaries jedoch nicht. Wenn diese angepasst werden müssen, muss der Index gelöscht und die Daten neu eingespielt werden.

Beispiel zum Aktualisieren der Replicas auf dem bestehenden Index “Person”:

Daten Typen

Vor dem Anlegen eines ersten Index und des Mappings lohnt es sich, die möglichen Datentypen der zu definierenden Felder anzusehen.

In dieser Liste befinden sich häufig genutzt Datentypen:

Datentyp Details
Boolean True / False
Numbers Sammelbegriff für einzelne Datentypen wie z.B. integer, long, double
Text Unstrukturierter Text, wird analysiert und ist nutzbar für die Volltextsuche
Keyword Erlaubt exaktes 1:1 zuzuordnen, z.B. Suche nach einer ganzen E-Mail-Adresse oder einer ID
Date Datum, wird als String ein- und ausgegeben und intern als Long gehandhabt
Object & Nested Strukturierte Objekte
Alias Definiert einen alternativen Namen für ein existierendes Feld

Weitere Datentypen und deren Definitionen befinden sich in der Elasticsearch-Dokumentation.

Arrays in Elasticsearch

Es gibt keinen gesonderten Array-Typ in Elasticsearch. Jedes Feld kann als Array gehandhabt werden. Wenn Felder dynamisch als Array angelegt werden, dann entscheidet der erste Wert über den Feldtyp.

In diesem Beispiel werden alle Zahlen des Arrays als Strings gehandhabt, obwohl der zweite JSON-Wert eine Zahl ist.

Der Unterschied zwischen Object und Nested

Wenn ein Feld vom Typ Object erstellt wird, können Unterfelder definiert werden. Bei der Standarddefinition Object werden diese Felder jedoch zusammengeführt.

In diesem Beispiel ist die Adresse vom Typ Object und hat ihre eigene Properties-Definition.

Es werden nun diese beiden Adressen gespeichert:

Adresse 1: Bahnhofstraße 1

Adresse 2: Schlossallee 7

In Elasticsearch werden die Felder dann wie folgt gespeichert:

Das führt jedoch dazu, dass eine Suche nach der Adresse „Schlossallee 1” ein gültiges Ergebnis liefert, obwohl die ursprüngliche Straße dieser Hausnummer nicht zugeordnet ist.

Soll dieser Zusammenhang der unterliegenden Felder behalten werden, muss der Datentyp nested verwendet werden. Wenn die Adresse bereits in das Mapping aufgenommen wurde, kann diese nicht mehr umdefiniert werden. Soll das Einfügen des Typ nested ausgeführt werden, muss zunächst der Index gelöscht und neu angelegt werden.

Mappings

Die Mappings enthalten alle Eigenschaften der Felder für die Dokumente. Wenn das Mapping nicht bei Index-Erstellung eingetragen wird, kann es mit der _mapping-Schnittstelle auf dem Index nachgetragen oder aktualisiert werden.

In der Kibana-Oberfläche unter Search/Indices kann nun die angelegte Instanz aufgerufen werden.

Abbildung: Kibana-Oberfläche

In der detaillierten Ansicht dieses Index kann auch das Index Mapping aufgerufen werden. Hier können alle konfigurierten Felder eingesehen werden.

Abbildung: Index mapping

Das Mapping kann jederzeit manuell oder dynamisch erweitert werden. Wenn das dynamische Erstellen erlaubt ist, kann aus Datensätzen mit neuen Felder automatisch eine Konfiguration angelegt werden. Hierbei kann es jedoch auch passieren, dass die Datentypen nicht richtig erkannt und dadurch falsch integriert werden.

Sobald das Feld angelegt wurde, kann der Typ nicht mehr geändert werden, sodass auch hier der ganze Index wieder für diese Anpassung gelöscht werden müsste. Wird das dynamische Mapping deaktiviert, führt dies dazu, dass Datensätze mit noch unbekannten Feldern nur teilweise gespeichert werden.

Um das dynamische Mapping auszuschalten, kann folgende Konfiguration verwendet werden:

Wenn die Kibana-Oberfläche nicht zur Verfügung steht, kann die Konfiguration des Index auch über die REST-Schnittstelle ausgelesen werden.

Dynamische Mappings

Wird für den Index das dynamische Mapping konfiguriert, können durch das Einfügen von Dokumenten neue Felder automatisch erkannt und in das Mapping aufgenommen werden.

Wenn ein Dokument auf einen nicht definierten Index und unbekanntes Mapping geschrieben wird, können diese ebenfalls automatisch generiert werden. Dafür muss zunächst die Option aktiviert werden, dass unbekannte Indices automatisch erstellt werden.

Ist diese Einstellung nicht aktiviert, wird unter Angabe eines unbekannten Index folgender Fehler ausgegeben:

"No such index [test2] and [action.auto_create_index] is [false]"

Im folgenden Beispiel existiert der ganze test-Index noch nicht. Indem ein Dokument in diesen Index geschrieben wird, generieren sich das zugehörige Mapping und die Felder.

In diesem Beispiel ist der JSON-Datentyp String, und dieser wird für das dynamische Mapping verwendet. Dadurch wird das Feld als Text mit zusätzlicher Keyword-Definition erzeugt. Weitere Standards des automatisierten Mappings befinden sich in der Tabelle des nächsten Abschnitts. Wird der Index abgerufen, kann das erwartete Ergebnis vorgefunden werden.

Index löschen

Aus dem vorherigen Beispiel wird klar, dass es hin und wieder vorkommen kann, dass ein Index gelöscht werden muss. Wichtig ist hierbei, vorher auf einen möglichen Datenverlust zu prüfen und dem entgegenzuwirken. Der automatisch erstellte Test-Index und seine Daten können wie folgt wieder entfernt werden:

Konfigurationsmöglichkeiten

Für das dynamische Mapping sind die Konfigurationsmöglichkeiten wie folgt:

False

  • Dynamisches Mapping ist deaktiviert.
  • Dokument mit unbekannten Werten wird akzeptiert, aber der Inhalt von neuen Felder wird verworfen und nur Bekanntes wird gespeichert.

True

  • Dynamisches Mapping ist aktiviert.

Strict

  • Dynamisches Mapping ist aktiviert.
  • Enthält das Dokument ein unbekanntes Feld, wird es abgelehnt.

Runtime

  • Dynamisches Mapping ist aktiviert.
  • Neue Felder werden als Laufzeit-Felder erzeugt und sind erst bei der Abfrage durchsuchbar. Dadurch kann die Abfrage langsamer werden.

Dynamische Mappings zur Laufzeit

Um ein dynamisches Mapping zur Laufzeit zu veranschaulichen, muss zunächst der bisherige Index umkonfiguriert werden:

Durch das Schreiben eines Dokuments mit unbekannten Werten werden diese nun als Runtime-Felder hinzugefügt. In diesem Beispiel wird das Feld für die Frau und Neffen generiert.

Wird das Index Mapping abgerufen, werden die neuen Werte im Block runtime aufgelistet:

Wenn nun eine einfache Suche auf den Namen eines Neffen ausgeführt wird, kann der Eintrag von Donald Duck gefunden werden und enthält die frisch angelegten Felder.

Definition der dynamisch gemappten Datentypen

Die folgenden Datentypen können automatisch erkannt werden:

JSON-Typ Dynamic: true Dynamic: Runtime
null Es wird kein Feld erstellt. Es wird kein Feld erstellt.
true / false boolean boolean
double float double
long long long
object object Es wird kein Feld erstellt.
array Abhängig vom ersten Wert im Array (darf nicht null sein) Abhängig vom ersten Wert im Array (darf nicht null sein)
string as Date date date
string as Numeric float / long double / long
string everything else text (keyword unterfeld) keyword

Die verschiedenen Mappings können auf unterschiedlichen Höhen definiert werden.
In diesem Fall werden Dokumente mit unbekannten Personendaten abgelehnt.

In diesem Beispiel wird an der Adresse dynamic: false gesetzt. Sollte die Adresse jetzt unbekannte Felder enthalten, wie z.B. die Koordinaten des Ortes, dann kann das Dokument trotzdem gespeichert werden, und die Koordinaten werden verworfen.

Dynamisches Feld Mapping

Field Data Typen werden automatisch erkannt (Liste oben). Alle weiteren Datentypen können nicht erkannt werden und müssen explizit gemappt werden. Das dynamische Mapping kann auch an einem Objekt definiert werden.

Numerische Erkennung

Die Erkennung von numerischen Werten ist standardmäßig deaktiviert. Das bedeutet, dass Strings nicht auf Zahlen geprüft werden, die als JSON String versendet werden. Sofern gewünscht kann die Erkennung über die Mapping-Einstellungen aktiviert werden.

Date

Diese Prüfung ist standardmäßig aktiviert. Die unbekannten String-Felder werden dann mit den Vorgaben aus dem dynamic_date_format abgeglichen. Wenn ein Treffer gefunden wird, wird das neue Datumsfeld in dem definierten Format hinzugefügt.

Der Default dieser beiden Erkennungen kann mit einer selbst definierten Mapping-Regel verändert werden. Dazu muss ein dynamisches Template geschrieben werden. In diesem können Werte definiert werden, die gematcht, aber auch die nicht gematcht werden sollen. Weitere Details zum Erstellen befinden sich in der Elasticsearch-Dokumentation.

Was ist Elasticsearch und wie richtet man die Suchmaschine ein? – Fazit

Elasticsearch ermöglicht es durch die dynamische Generierung, mit sehr geringem Aufwand Daten strukturiert abzulegen. Durch die Unterstützung von Kibana können Konfigurationen zudem sehr einfach über eine Oberfläche angepasst und eingesehen werden.

Beim initialen Erstellen eines Index macht es für Produktivumgebungen Sinn, das Konzept von Shards und Replicas zu verstehen, sodass eine gültige und vor allem sinnvolle Konfiguration für das jeweilige Cluster erstellt werden kann.

Bei allen Umgebungen ist es sinnvoll, sich mit den Vor- und Nachteilen einer dynamischen Generierung und den möglichen Ergebnissen auseinanderzusetzen. Sollten unglücklicherweise falsche Datentypen angelegt werden, können diese nicht korrigiert werden, ohne den Index und die gespeicherten Daten zu löschen.

Für die ersten Schritte ist eine dynamische Generierung sehr komfortabel, um schnell starten zu können. Auch später kann eine gezielte Konfiguration sehr nützlich sein, um zum Beispiel Verschachtelungen unbekannter Größe abzubilden.

Nach den Grundlagen der Einrichtung und dem Erstellen erster Datenstrukturen wird sich der nächste Beitrag auf die extrem performante Suche fokussieren.

Bis dahin, happy elastic creating!

Photo by Agence Olloweb on Unsplash

Lisa Messerli

Große Auswahl an günstigen Domain-Endungen – schon ab 0,08 € /Monat
Jetzt Domain-Check starten