zum Inhalt springen
Kontakt

Moderne Suchfunktionen für Softwarelösungen - mit Elasticsearch

Cyrill Jabornegg

Viel Zeit in unserem Alltag verbringen wir damit, etwas zu suchen. Damit meine ich nicht verlegte Autoschlüssel oder Brieftaschen – das sind Mysterien für sich.

Die Suche, auf die ich eingehen möchte, geschieht am Computer, am Smartphone, am Tablet oder gar am Fernseher. Stellen Sie sich die folgende Situation vor: Sie befinden sich mit Arbeitskollegen in der morgendlichen Kaffeepause. Einer Ihrer Kollegen berichtet Ihnen von einem neuen Produkt: Das Vorlagentool Docugate könne aus der Cloud genutzt werden! Sie sind von misstrauischer Natur und möchten dies gerne selber sehen, also zücken Sie prompt Ihr Smartphone und tippen «Docugate Web» in die Suchmaschine Ihrer Wahl ein.

Wie kommt es nun, dass die für Sie relevanten Suchergebnisse scheinbar immer innerhalb der ersten fünf Ergebnisse ersichtlich sind? Hier lohnt es sich, einen Blick hinter die Kulissen von Suchmaschinen zu werfen und diese beispielsweise SQL-basierten Softwarelösungen gegenüberzustellen.

 

Filterung vs. Suche

Womöglich sind Sie mit den SQL-Datenbanktechniken vertraut. Sie haben verschiedene Tabellen, welche zueinander in Beziehung stehen. Nun können Sie Abfragen auf einer Datenbank dieser Art einsetzen. Hier können Sie auch suchen. Führen Sie sich das folgende Beispiel zu Gemüte.

SELECT * FROM [Products] WHERE [Rating] = 5.0
SELECT * FROM [Products] WHERE [Rating] = 5.0
SELECT * FROM [Products] WHERE [Rating] = 5.0

Das Resultat könnte wie folgt aussehen:

Name Rating
Docugate 5.0

 

Hierbei handelt es sich um einen Filter. Bei den meisten SQL-Suchabfragen handelt es sich um Filterabfragen. Kommen längere Textpassagen ins Spiel, so können wir auch etwas komplexere Suchabfragen eingeben.

SELECT * FROM [TextComponents]
WHERE [Content] LIKE '%Hypotheken%' OR [Content] LIKE '%Zinssatz%'
SELECT * FROM [TextComponents] WHERE [Content] LIKE '%Hypotheken%' OR [Content] LIKE '%Zinssatz%'
SELECT * FROM [TextComponents]
WHERE [Content] LIKE '%Hypotheken%' OR [Content] LIKE '%Zinssatz%'

Diese Abfrage liefert Ihnen alle Textbausteine, welche mindestens eines der Wörter «Hypotheken» oder «Zinssatz» enthalten. Soweit so gut. Was fehlt denn dieser Suche noch?

Stellen Sie sich vor, bei den Suchkriterien handelt es sich um Benutzereingaben im Suchfeld einer Applikation. Dem Benutzer werden so Textbausteine aufgelistet, welche ein Wort oder mehrere seiner Wörter beinhalten.

An diesem Punkt kommen verschiedene Problematiken ins Spiel:

  • Die Resultate geben dem User keinen Anhaltspunkt, wie viele der Wörter aus seiner Suche tatsächlich im Textbaustein vorkommen. Somit ist es nicht ohne Weiteres möglich, die Relevanz der Ergebnisse in der Anzeige zu berücksichtigen. Das finden Sie nicht so schlimm? Fragen Sie sich, wann Sie zuletzt zur zweiten Seite einer Google-Suche vorgeschaltet haben und welche Auswirkungen dies auf Ihren Gemütszustand hatte.
  • Der Benutzer muss genau wissen, welche Wörter er suchen muss – muss er das nicht immer? Nein! Bei der oben beschriebenen Suche könnte der Benutzer Ergebnisse finden wollen, in denen «Hypothek» – also die singuläre Form – vorkommt. Diese wird er aber so nie finden.

Nun stellt sich die Frage: Möchten Sie im Alltag mit diesen Einschränkungen beim Suchen leben? Falls Sie Software entwickeln, garantiere ich Ihnen, Ihre Anwender werden diese Frage höchstwahrscheinlich vehement verneinen.

 

Dokumentenbasierte NoSQL-Lösung mit Suchindizes

Wenn Sie die oben beschriebene Problematik mit einer bestehenden SQL-Lösung vermeiden wollen, werden Sie sehr viel neue Logik in Ihre Applikation einbauen müssen. Diese Entwicklung wird nicht nur aufwändig, sie bringt auch einiges an Komplexität mit sich.

Spätestens zu diesem Zeitpunkt sollte sich jeder Softwareentwickler die altbekannte Frage stellen: Bin ich wohl der Erste, der auf diese Problematik stösst? Wie beinahe immer lautet die Antwort: Nein. Es handelt sich dabei um ein verbreitetes Bedürfnis.

Diesem Umstand entsprechend gibt es bereits auch verschiedene Softwarelösungen, welche dem Problem Abhilfe schaffen. Elasticsearch ist eines dieser Produkte.

Bei Elasticsearch handelt es sich um einen Suchserver. Anders als bei SQL-Servern werden die Daten hier nicht in Tabellen mit Spalten gehalten und in grossen Binärfiles gespeichert. Elasticsearch speichert Datensätze als einzelne JSON-Dokumente. Diese werden in sogenannten Indizes gehalten. Es handelt sich also um eine dokumentenbasierte NoSQL-Lösung. Eine Einführung in NoSQL finden Sie hier.

Elasticsearch bildet eine Abstraktion der ebenfalls verbreiteten Software Lucene aus dem Hause Apache. Im Unterschied zu letzterer wird Elasticsearch jedoch nicht als Bibliothek in Softwarelösungen eingebunden, sondern als Webservice mit HTTP-Schnittstelle verwendet.

Um sich im Umfeld von Elasticsearch zurechtzufinden, ist es hilfreich, die folgenden Begriffe einordnen zu können:

  • Cluster: Elasticsearch wurde als verteilte Applikation entwickelt und läuft somit über mehrere Hosts verteilt.
  • Node: Ein Node ist ein Computer, der Teil eines Clusters (hier: Elasticsearch) ist.
  • (Primary) Shard: Dies bezeichnet einen Teil eines Indexes in Elasticsearch. Jeder (primary) Shard kann Daten lesen, schreiben, aktualisieren und löschen. Hier ist die Abstrahierung von Apache Lucene zu sehen – ein Shard in Elasticsearch entspricht einem Index in Lucene.
  • Replica: Replicas spiegeln den Dateninhalt von Shards und erhöhen so die Performanz bei Lesezugriffen. Schreibvorgänge führen sie keine aus.
  • Index: Ein Index fasst zusammengehörende Daten (also JSON-Dokumente) in einer Gruppe zusammen. Er besteht aus verschiedenen Shards, welche (nach Möglichkeit) gleichmässig auf alle Nodes im Cluster verteilt werden.

 

Der Analyzing-Prozess & Mapping

So weit, so gut. Doch wie löst dies nun die Suchprobleme mit Singular/Plural oder Bewertung unseres Beispiels?

Bevor Daten in Elasticsearch gesucht werden können, müssen sie angeliefert werden. Dies nennt man Indexierung. Während des Schritts der Indexierung wird auf Textfeldern das sogenannte Analyzing durchgeführt. Pro Feld in einem Index kann ein Analyzer definiert werden. Ein Analyzer ist eine Kombination der folgenden Komponenten, die der Inhalt eines Feldes reihenweise durchläuft:

  1. Character Filters: Einer (oder mehrere sequentiell abgearbeitete) Zeichenfilter erhalten den Originaltext (bzw. den Output des vorhergehenden Zeichenfilters) und können Zeichen entfernen. Dies wird z.B. zum Entfernen von HTML-Elementen verwendet.
  2. Tokenizer: Jeder Analyzer hat nur einen Tokenizer. Er erhält den Output des letzten Zeichenfilters und bricht den gesamten Inhalt in Tokens auf – zum Beispiel in einzelne Wörter.
  3. Token filters: Der erhaltene Stream von Tokens wird nun durch einen oder mehrere Token-Filter verarbeitet. Es können Tokens hinzugefügt, verändert oder entfernt werden. Beispiele für die Verwendung von Token-Filtern sind «lowercase», «stop words» und Synonyme.

Elasticsearch stellt eine breite Auswahl an «built-in» Filtern bereit, welche viele Standardfälle – z.B. das Analysieren deutschsprachiger Fliesstexte – ausreichend abdecken.

Die Definition dieser Analyzers pro Feld erfolgt in der Definition eines Index. Diese heisst in Elasticsearch «Mapping» und kann per HTTP-GET Request auf /{index}/_mapping abgefragt werden.

Elasticsearch ist – wie viele dokumentenbasierte Datenbanken – schemalos. Genau wie diese anderen Datenbanken erstellt Elasticsearch im Standardfall automatisch eine Art Schema für die angelieferten Daten. Dabei handelt es sich um das Mapping. Dabei gilt es, Vorsicht zu bewahren: Ein Mapping kann zwar ergänzt werden, jedoch kann ein erstelltes Mapping nicht verändert werden! Hier ist eine Neuindizierung des gesamten Datenbestandes notwendig.

Durch den Analyzing-Prozess werden Wörter auf ihre Stammform reduziert und für die Suche nutzlose «stop words» entfernt. So wird auch das Problem mit Ein- und Mehrzahlbegriffen in der Suche bewältigt.

Anschliessend werden die Daten in einem invertierten Index über mehrere Shards verteilt abgelegt.

 

Bewertung der Suchergebnisse via Scoring-Funktion

Eine Rangordnung für Suchergebnisse berechnet Elasticsearch out of the box und sortiert die Suchergebnisse dementsprechend. Wer diese Scoring-Funktion im Detail anschauen möchte, findet eine ausführliche Dokumentation auf der Webseite von Apache Lucene.

 

Suchanfragen für Volltextsuche

Elasticsearch ist für viele Anwendungsfälle bereits mit der einfachen Volltextsuche ausreichend hilfreich. Eine Volltextsuche kann wie folgt aussehen:

GET /products/_search?q = docugate HTTP / 1.1
Host: {hostname}: 9200
GET /products/_search?q=docugate HTTP/1.1 Host: {hostname}:9200
GET /products/_search?q=docugate HTTP/1.1
Host: {hostname}:9200

Die etwas komplexere Suche von oben liesse sich wie folgt in eine Request mit JSON-Body übersetzen:

POST /textcomponents HTTP / 1.1
Host: {hostname}: 9200
Content-Type: application/json
POST /textcomponents HTTP/1.1 Host: {hostname}:9200 Content-Type: application/json
POST /textcomponents HTTP/1.1
Host: {hostname}:9200
Content-Type: application/json
{
"query": {
"bool": {
"should": [
{
"match": {
"content": "Hypotheken"
}
},
{
"match": {
"content": "Zinssatz"
}
}
]
}
}
}
{ "query": { "bool": { "should": [ { "match": { "content": "Hypotheken" } }, { "match": { "content": "Zinssatz" } } ] } } }
{
"query": {
"bool": {
"should": [
{
"match": {
"content": "Hypotheken"
}
},
{
"match": {
"content": "Zinssatz"
}
}
]
}
}
}

 

Die Elasticsearch-Dokumentation behandelt die Search API in voller Tiefe. Für alle Leser, denen sich nun die Haare sträuben, Elasticsearch bietet auch ein komfortables SQL-Interface an. Hier können Abfragen mit der gewohnten SQL-Syntax abgesetzt oder gar in die Elasticsearch-Syntax übersetzt werden.

POST /_sql?format = txt HTTP / 1.1
Host: {hostname}: 9200
Content-Type: application/json
POST /_sql?format=txt HTTP/1.1 Host: {hostname}:9200 Content-Type: application/json
POST /_sql?format=txt HTTP/1.1
Host: {hostname}:9200
Content-Type: application/json
{
"query":
"""
SELECT * FROM "textcomponents" WHERE "content" LIKE '%Hypothek%' OR "content" LIKE '%Zinssatz%'
"""
}
{ "query": """ SELECT * FROM "textcomponents" WHERE "content" LIKE '%Hypothek%' OR "content" LIKE '%Zinssatz%' """ }
{
"query":
"""
SELECT * FROM "textcomponents" WHERE "content" LIKE '%Hypothek%' OR "content" LIKE '%Zinssatz%'
"""
}

 

Das SQL-Interface ist ein X-Pack Feature und steht in der ebenfalls kostenfreien Basic-Version von Elasticsearch zur Verfügung. In der unter Apache 2.0 veröffentlichten OSS-Version kann das SQL-Interface jedoch nicht genutzt werden.

 

Wie weiter?

Über Elasticsearch könnte man so einige Blogposts veröffentlichen – und dies haben auch schon viele Leute gemacht! Eine einfache Websuche liefert häufig verschiedenste Einblicke und Tipps, die vom Einstieg bis zum Betrieb in der Produktion reichen. Die beste Referenz ist gemäss der Einschätzung des Autors die sehr gute offizielle Dokumentation.

Sie sehen, Suche ist nicht gleich Suche. Viele Softwarelösungen, die schon länger im Dienst sind, lassen moderne Suchfeatures vermissen. Elasticsearch als Suchserver mit http/REST Schnittstelle kann häufig vergleichsweise unproblematisch eingebunden werden (vom operationellen Zusatzaufwand abgesehen).

 

Sollten Sie sich in den oben beschriebenen Situationen wiedererkennen, erwägen Sie Elasticsearch als Lösung. Gerne unterstützen wir Sie natürlich bei der Einführung und Umsetzung. Zögern Sie also nicht, einen Kommentar zu hinterlassen oder kontaktieren Sie uns für ein unverbindliches Beratungsgespräch zu Ihrer individuellen Lösung:

Beratungstermin vereinbaren!