Wer eine leis­tungs­star­ke Voll­text­su­che benötigt, wählt meist Apache Solr. Und dieses Projekt ist auch weiterhin eine gute Wahl – doch seit 2010 bietet der Markt eine in­ter­es­san­te Al­ter­na­ti­ve: Ela­s­tic­se­arch. Genau wie Solr basiert auch Ela­s­tic­se­arch auf Apache Lucene, wartet aber mit anderen Features auf. Wir erläutern die Merkmale des Such­ser­vers und erklären Ihnen in unserem Ela­s­tic­se­arch-Tutorial, wie Sie die Voll­text­su­che für Ihr eigenes Projekt im­ple­men­tie­ren.

In­zwi­schen gehört Ela­s­tic­se­arch zu den wich­tigs­ten Voll­text­such­ma­schi­nen im Internet. Auch große Un­ter­neh­men nutzen die Software: Facebook bei­spiels­wei­se arbeitet seit mehreren Jahren er­folg­reich mit Ela­s­tic­se­arch und auch GitHub, Netflix, Sound­Cloud und Zalando setzen auf die er­folg­rei­che Such­ma­schi­ne.

Was ist Ela­s­tic­se­arch?

An­ge­sichts der Menge an In­for­ma­tio­nen auf manchen Websites lässt sich eine hohe Be­nut­zer­freund­lich­keit nur ga­ran­tie­ren, wenn man eine funk­ti­ons­tüch­ti­ge Voll­text­su­che im­ple­men­tiert. Wer nicht auf Angebote von Google oder Bing zu­rück­grei­fen möchte, um seinen Besuchern eine Such­funk­ti­on an­zu­bie­ten, der muss statt­des­sen eine eigene Such­funk­ti­on einbetten. Dies geht zum Beispiel mit Ela­s­tic­se­arch. Das Open-Source-Projekt basiert auf dem ebenfalls frei ver­füg­ba­ren Apache Lucene.

Ela­s­tic­se­arch bietet die Vorteile des stabilen Vor­gän­gers und baut diese mit weiteren Features aus. Genau wie bei Lucene funk­tio­niert die Suche über einen Index: Statt bei einer Such­an­fra­ge alle Dokumente zu un­ter­su­chen, überprüft das Programm einen zuvor er­stell­ten Index der Dokumente, in dem alle Inhalte auf­be­rei­tet ge­spei­chert sind. Dieser Prozess benötigt sehr viel weniger Zeit als die Suche in sämt­li­chen Do­ku­men­ten.

Während Sie mit Lucene voll­kom­men freie Hand haben, wo und wie Sie die Voll­text­su­che einsetzen, müssen Sie bei dieser Software al­ler­dings voll­kom­men von Null anfangen. Ela­s­tic­se­arch er­mög­licht Ihnen hingegen für den Einsatz im World Wide Web einen schnel­le­ren Einstieg. So ist es mit Ela­s­tic­se­arch in kurzer Zeit möglich, einen stabilen Such­ser­ver auf­zu­bau­en, der zudem noch leicht auf mehrere Maschinen verteilt werden kann.

Mehrere Knoten (ver­schie­de­ne Server) schließen sich zusammen und bilden einen Cluster. Dabei kommt das so­ge­nann­te Sharding zum Einsatz: Ela­s­tic­se­arch bricht hierbei den Index auf und verteilt die einzelnen Teile (shards) auf mehrere Knoten. Dadurch wird auch die Re­chen­last auf­ge­teilt – bei großen Projekten läuft die Voll­text­su­che so deutlich stabiler. Für mehr Si­cher­heit sorgt man, indem man die Shards zu­sätz­lich auf mehrere Knoten kopiert.

Ela­tic­se­arch basiert – genau wie Lucene – auf der ob­jekt­ori­en­tier­ten Pro­gram­mier­spra­che Java. Die Such­ma­schi­ne gibt Such­ergeb­nis­se im JSON-Format aus und liefert diese über einen REST-Web­ser­vice aus. Das API macht es sehr leicht, die Such­funk­ti­on in eine Website ein­zu­bau­en.

Zudem bietet Ela­s­tic­se­arch mit Kibana, Beats und Logstash – zusammen als Elastic-Stack bekannt – prak­ti­sche Zu­satz­diens­te, mit denen Sie die Voll­text­su­che ana­ly­sie­ren können. Die Firma Elastic, die hinter der Ent­wick­lung von Ela­s­tic­se­arch steckt und vom Erfinder des Programms gegründet wurde, bietet zudem auch kos­ten­pflich­ti­ge Dienste an – bei­spiels­wei­se Cloud-Hosting.

Was bietet Ela­s­tic­se­arch, was Google & Co. nicht haben?

Es gibt doch bereits Google – und dessen populäre Such­funk­ti­on können Sie pro­blem­los in die eigene Website in­te­grie­ren. Warum also sollte man sich für den müh­sa­me­ren Schritt ent­schei­den und eine eigene Such­ma­schi­ne mit Ela­s­tic­se­arch bauen? Eine mögliche Antwort: Mit Google Custom Search (GCS) machen Sie sich abhängig vom Such­ma­schi­nen­rie­sen und lassen (zumindest in der kos­ten­lo­sen Version) Werbung in den Such­ergeb­nis­sen zu. Das können Sie mit Ela­s­tic­se­arch umgehen: Der Code ist Open Source, und wenn Sie eine Voll­text­such­funk­ti­on auf­ge­setzt haben, gehört diese auch Ihnen – Sie sind von niemandem abhängig.

Darüber hinaus können Sie Ela­s­tic­se­arch ganz nach Ihren Wünschen anpassen. Wenn Sie zum Beispiel eine eigene Online-Plattform oder einen E-Shop betreiben, können Sie die Such­funk­ti­on so ein­rich­ten, dass Sie mithilfe von Ela­s­tic­se­arch auch die Profile der an­ge­mel­de­ten Nutzer durch­su­chen können. Bei solchen An­wen­dungs­be­rei­chen stößt GCS an seine Grenzen.

Ela­s­tic­se­arch vs. Apache Solr: Was sind die wich­tigs­ten Un­ter­schie­de?

Sowohl Ela­s­tic­se­arch als auch Apache Solr basieren auf Lucene, wurden aber zu ei­gen­stän­di­gen Angeboten wei­ter­ent­wi­ckelt. Viele Nutzer fragen sich jedoch, für welches Projekt sie sich ent­schei­den sollten. Auch wenn Ela­s­tic­se­arch etwas jünger ist und im Gegensatz zu Solr nicht durch die erfahrene Apache-Community gestützt wird, hat man das Schwes­ter­pro­jekt in­zwi­schen in puncto Nut­zer­zah­len überholt. Grund dafür ist vor allem die ein­fa­che­re Im­ple­men­tie­rung. Darüber hinaus ist Ela­s­tic­se­arch vor allem aufgrund seines Umgangs mit dy­na­mi­schen Daten beliebt: Durch ein spe­zi­el­les Caching-Verfahren schafft es Ela­s­tic­se­arch, dass Än­de­run­gen nicht im gesamten globalen Cache ein­ge­tra­gen werden müssen. Statt­des­sen reicht es, ein kleines Segment zu ändern. Das macht Ela­s­tic­se­arch flexibler.

Letzten Endes hat die Ent­schei­dung aber oft lediglich mit den un­ter­schied­li­chen Ansätzen im Zuge von Open Source zu tun. Solr ver­pflich­tet sich ganz dem Gedanken der Apache Software Foun­da­ti­on: Community over Code. Jeder Beitrag am Code wird ernst­ge­nom­men und die Ge­mein­schaft ent­schei­det gemeinsam, welche Er­gän­zun­gen und Wei­ter­ent­wick­lun­gen es in den finalen Code schaffen. Bei der Wei­ter­ent­wick­lung von Ela­s­tic­se­arch ist das anders: Auch dieses Projekt ist Open Source und wird unter einer freien Apache-Lizenz angeboten – al­ler­dings bestimmt allein das Team von Elastic, welche Än­de­run­gen es in den Code schaffen. Gegen diese Gate­kee­per-Men­ta­li­tät wehren sich einige Ent­wick­ler und ent­schei­den sich daher für Solr.

Ela­s­tic­se­arch-Tutorial

Wenn man beginnt, mit Ela­s­tic­se­arch zu arbeiten, sollte man sich zunächst mit einigen Grund­be­grif­fen aus­ein­an­der­set­zen. So ist zum Beispiel die In­for­ma­ti­ons­struk­tur er­wäh­nens­wert:

  • Index: Eine Such­an­fra­ge bei Ela­s­tic­se­arch gilt nie den Inhalten selbst, sondern immer dem Index. In diesem sind alle Inhalte sämt­li­cher Dokumente ge­spei­chert und bereits auf­be­rei­tet – dadurch erfordert die Suche nur wenig Zeit. Es handelt sich um einen so­ge­nann­ten inverted index: Zu jedem Such­be­griff ist der Ort angegeben, an dem sich der Begriff finden lässt.
     
  • Document: Ausgang für den Index sind die Dokumente, in denen Daten vorkommen. Sie müssen nicht zwingend voll­stän­di­ge Texte sein (bei­spiels­wei­se Blog­ar­ti­kel) – es reichen bloße Dateien mit In­for­ma­tio­nen.
     
  • Field: Ein Dokument wiederum besteht aus mehreren Feldern. Neben dem ei­gent­li­chen In­halts­feld gehören auch weitere Metadaten zu einem Dokument. So lässt sich mit Ela­s­tic­se­arch zum Beispiel gezielt nach Metadaten zum Autor oder zum Ent­ste­hungs­zeit­punkt suchen.

Übrigens: Wenn wir von Auf­be­rei­tung der Daten sprechen, geht es in erster Linie um das To­ke­ni­zing. Hierbei erstellt ein Al­go­rith­mus aus einem kom­plet­ten Text einzelne Begriffe. Für die Maschine gibt es erst mal so etwas wie Wörter nicht: ein Text besteht aus einer langer Zei­chen­fol­ge und ein Buchstabe hat für den Computer den gleichen Wert wie ein Leer­zei­chen. Damit ein Text also sinnvoll auf­be­rei­tet wird, muss dieser erst einmal in Tokens zerlegt werden. Dazu wird zum Beispiel White­space – also Leer­zei­chen und Leer­zei­len – als Mar­kie­run­gen für Wörter an­ge­nom­men. Darüber hinaus wird beim Auf­be­rei­ten auch nor­ma­li­siert: Wörter werden ein­heit­lich klein ge­schrie­ben und Satz­zei­chen ignoriert. Diese Methoden hat Ela­s­tic­se­arch alle von Apache Lucene über­nom­men.

Hinweis

Im folgenden Tutorial arbeiten wir mit der Version 6.3.0 von Ela­s­tic­se­arch. Nutzen Sie eine andere Version, könnten unter Umständen einige Code-Beispiele oder An­lei­tungs­schrit­te anders funk­tio­nie­ren.

In­stal­la­ti­on

Die be­nö­tig­ten Dateien für Ela­s­tic­se­arch sind frei auf der of­fi­zi­el­len Website von Elastic verfügbar. Die Dateien werden dort als ZIP- oder tar.gz-Pakete angeboten, weshalb sie sich unter Linux und Mac auch ganz einfach per Konsole in­stal­lie­ren lassen.

Hinweis

Elastic bietet Ela­s­tic­se­arch in zwei un­ter­schied­li­chen Paketen an. Die Stan­dard­ver­si­on be­inhal­tet auch kos­ten­pflich­ti­ge Features, die Sie in einer Trial-Version für einige Zeit aus­pro­bie­ren können. Solche Pakete hingegen, die mit OSS (Open-Source-Software) ge­kenn­zeich­net sind, enthalten aus­schließ­lich freie Be­stand­tei­le, die unter der Lizenz Apache 2.0 ver­öf­fent­licht wurden.

Für ZIP:

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.zip
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.zip.sha512
shasum -a 512 -c elasticsearch-oss-6.3.0.zip.sha512 
unzip elasticsearch-oss-6.3.0.zip
cd elasticsearch-6.3.0

Für tar.gz:

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.tar.gz
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.tar.gz.sha512
shasum -a 512 -c elasticsearch-oss-6.3.0.tar.gz.sha512 
tar -xzf elasticsearch-oss-6.3.0.tar.gz
cd elasticsearch-6.3.0

Laden Sie zunächst das Paket herunter und zudem noch die Hash-Prüfsumme (SHA512), die Sie im dritten Schritt auch über­prü­fen. An­schlie­ßend entpacken Sie das Paket und wechseln in den ent­spre­chen­den Ordner.

Das ZIP-Archiv lässt sich auch her­un­ter­la­den und für die In­stal­la­ti­on unter Windows nutzen, denn in dem Paket ist eine Batch-Datei enthalten, die Sie ausführen können. Al­ter­na­tiv stellt Elastic in­zwi­schen aber auch einen MSI-Installer zur Verfügung – dieser befindet sich al­ler­dings noch in der Beta-Phase. Die In­stal­la­ti­ons­da­tei des letzt­ge­nann­ten enthält ein gra­fi­sches Interface, das Sie präzise durch die In­stal­la­ti­on führt.

Hinweis

Da Ela­s­tic­se­arch auf Java basiert, muss diese Pro­gram­mier­spra­che auch auf Ihrem System in­stal­liert sein. Laden Sie sich dafür am besten das Java De­ve­lo­p­ment Kit (JDK) kostenlos von der of­fi­zi­el­len Website herunter.

Führen Sie Ela­s­tic­se­arch nun über die Konsole aus, indem Sie in den ent­spre­chen­den bin-Ordner na­vi­gie­ren und „ela­s­tic­se­arch eingeben – egal, ob unter Linux, Mac oder Windows. Öffnen Sie dann einen Browser Ihrer Wahl und rufen Sie folgenden Port des localhost auf: "http://localhost:9200/" Wenn Sie Ela­s­tic­se­arch korrekt in­stal­liert haben und auch Java richtig ein­ge­stellt ist, sollten Sie nun auf die Voll­text­su­che zugreifen können.

Mit Ela­s­tic­se­arch kom­mu­ni­zie­ren Sie über das REST-API, deshalb benötigen Sie zu­sätz­lich einen ent­spre­chen­den Client. Es empfiehlt sich, hierfür Kibana ein­zu­set­zen (ebenfalls ein kos­ten­frei­es Open-Source-Angebot von Elastic). Mit diesem Programm können Sie Ela­s­tic­se­arch direkt im Browser verwenden. Dafür rufen Sie dort einfach http://localhost:5601/ auf und können dann auf eine grafische Be­nut­zer­ober­flä­che zugreifen. Wie Sie Kibana richtig in­stal­lie­ren und ein­rich­ten, erfahren Sie in unserem Tutorial zu Kibana. In Kibana und jedem anderen Client können Sie mit den HTTP-Methoden PUT, GET, POST und DELETE Kommandos an Ihre Voll­text­su­che senden.

Index

In einem ersten Schritt müssen Sie zunächst Ihren Index erstellen und diesen mit Daten anfüttern. Dafür können Sie zwei ver­schie­de­nen HTTP-Methoden anwenden: POST und PUT. Sie benutzen PUT, wenn Sie für den Eintrag eine spe­zi­fi­sche ID angeben möchten. Bei POST erstellt Ela­s­tic­se­arch selbst eine ID. In unserem Beispiel möchten wir eine Bi­blio­gra­fie ein­rich­ten. Jeder Eintrag soll den Namen des Autors, den Titel des Werks und das Er­schei­nungs­jahr enthalten.

POST bibliography/novels
{
"author": "Isabel Allende",
"title": "La casa de los espíritus",
"year": "1982"
}

Wenn Sie die Eingabe so verwenden möchten, müssen Sie die Konsole von Kibana verwenden. Falls Sie aber nicht auf diese Software zu­rück­grei­fen wollen, können Sie al­ter­na­tiv auch cURL nutzen. Statt des vor­an­ge­gan­gen Befehls müssen Sie dann folgendes in die Kom­man­do­zei­le eingeben:

curl -XPOST http://localhost:9200/bibliography/novels -H "Content-Type: application/json" -d '{"author": "Isabel Allende", "title": "La casa de los espíritus", "year": "1982"}'

Nach­fol­gend zeigen wir Ihnen nur den Code für Kibana – dieser lässt sich aber pro­blem­los in die Syntax von cURL über­tra­gen.

Ela­s­tic­se­arch sollte, wenn Sie alles korrekt ein­ge­tra­gen haben, folgende Angaben zu Beginn der Meldung zu­rück­ge­ben:

{
    "_index": "bibliography",
    "_type": "novels",
    "_id": "AKKKIWQBZat9Vd0ET6N1",
    "_version": 1,
    "result": "created",
}

An dieser Stelle wird deutlich, dass Ela­s­tic­se­arch nun einen Index mit dem Namen bi­blio­gra­phy und dem Typ novels findet. Da wir die POST-Methode verwendet haben, ge­ne­rier­te Ela­s­tic­se­arch au­to­ma­tisch eine ein­zig­ar­ti­ge ID für unseren Eintrag. Der Eintrag befindet sich derzeit in der ersten Version und wurde kürzlich erstellt (created).

Hinweis

Bei einem Typ (_type) handelte es sich in Ela­s­tic­se­arch früher um eine Art Un­ter­ka­te­go­rie. Über sie war es möglich, mehrere Typen unter einem Index zu ver­sam­meln. Dies führte aber zu un­ter­schied­li­chen Problemen und so plant Elastic derzeit, solche Typen nicht mehr zu nutzen. In Version 6.x ist _type noch enthalten, es ist aber nicht mehr möglich, mehrere Typen unter einem Index zu ver­sam­meln. Ab Version 7.0 ist geplant, Typen komplett zu streichen, wie die Ent­wick­ler in ihrem Blog erklären.

Sie können mit PUT Ihrem Eintrag auch eine ganz bestimmte ID geben. Diese wird in der ersten Zeile des Codes fest­ge­legt. PUT benötigen Sie auch dann, wenn Sie einen be­stehen­den Eintrag abändern möchten.

PUT bibliography/novels/1
{
"author": "William Gibson",
"title": "Neuromancer",
"year": "1984"
}

Der folgende Output ähnelt sehr dem, den wir auch mit der POST-Methode erhalten, al­ler­dings gibt uns Ela­s­tic­se­arch die ID wieder, die wir dem Eintrag in der ersten Zeile gegeben haben. Die Rei­hen­fol­ge der Angabe lautet immer _index/_type/_id.

{
    "_index": "bibliography",
    "_type": "novels",
    "_id": "1",
    "_version": 1,
    "result": "created",
}

Mit dem PUT-Befehl und der ein­deu­ti­gen ID können wir Einträge auch abändern:

PUT bibliography/novels/1
{
"author": "William Gibson",
"title": "Count Zero",
"year": "1986"
}

Da der Eintrag mit der ID 1 bereits besteht, verändert Ela­s­tic­se­arch diesen nur, statt einen neuen zu erstellen. Das spiegelt sich auch im Output wider:

{
    "_index": "bibliography",
    "_type": "novels",
    "_id": "1",
    "_version": 2,
    "result": "updated",
}

Die Ver­si­ons­num­mer ist auf 2 gestiegen und als result erhalten wir updated statt created. Das gleiche können Sie selbst­ver­ständ­lich auch mit einer zufällig von Ela­s­tic­se­arch er­stell­ten ID schaffen – durch die Länge und die Unordnung der Zeichen wäre die weitere Arbeit aber um einiges um­ständ­li­cher. Das Verfahren bedeutet auch, dass Ela­s­tic­se­arch einen Eintrag einfach über­schreibt, wenn Sie bei­spiels­wei­se mit den ID-Nummern durch­ein­an­der kommen. Um ver­se­hent­li­che Über­schrei­bun­gen zu vermeiden, können Sie den _create-Endpoint verwenden:

PUT bibliography/novels/1/_create
{
"author": "Mary Shelley",
"title": "Frankenstein; or, The Modern Prometheus",
"year": "1818"
}

Da im Index bereits ein Eintrag mit der ID 1 vorhanden ist, bekommen Sie eine Feh­ler­mel­dung angezeigt.

Wenn Sie Än­de­run­gen an einem Eintrag wie be­schrie­ben vornehmen, erzeugen Sie streng­ge­nom­men einen komplett neuen Eintrag und müssen daher auch alle Angaben komplett eintragen. Statt­des­sen können Sie aber auch nur Ver­än­de­run­gen in den be­stehen­den Eintrag in­te­grie­ren. Hierfür nutzen Sie den Endpoint _update:

POST bibliography/novels/1/_update
{
"doc": {
    "author": "Franz Kafka",
"genre": "Horror"
    }
}

Nun haben wir dem Eintrag ein zu­sätz­li­ches Feld hin­zu­ge­fügt und ein be­stehen­des Feld verändert, ohne die anderen dabei zu löschen – al­ler­dings nur im Vor­der­grund. Im Hin­ter­grund hat Ela­s­tic­se­arch dennoch den kom­plet­ten Eintrag neu angelegt, dafür aber die bereits be­stehen­den Inhalte selbst­stän­dig eingefügt.

Prin­zi­pi­ell haben wir bisher einfach einen Eintrag in eine Datenbank ge­schrie­ben und können diesen daher auch direkt wieder abrufen. Dafür verwenden wir die GET-Methode.

GET bibliography/novels/1

Sie können sich den Eintrag aber auch ganz einfach im Browser anzeigen lassen:

http://localhost:9200/bibliography/novels/1

Im Output zeigt uns Ela­s­tic­se­arch alle Details unseres Eintrags:

{
    "_index": "bibliography",
    "_type": "novels",
    "_id": "1",
    "_version": 2,
    "found": true,
    "_source": {
        "author": "William Gibson",
        "title": “Count Zero",
        "year": "1984"
    }
}

Ergänzend zu den bereits bekannten In­for­ma­tio­nen finden Sie unter _source die Felder des Dokuments. Außerdem in­for­miert uns Ela­s­tic­se­arch darüber, dass tat­säch­lich ein Eintrag gefunden wurde. Wenn Sie versuchen, einen nicht be­stehen­den Eintrag auf­zu­ru­fen, würde keine Feh­ler­mel­dung auf­tau­chen. Statt­des­sen meldet Ela­s­tic­se­arch "found": false und es gibt keine Einträge unter _source.

Sie haben darüber hinaus auch die Mög­lich­keit, nur bestimmte In­for­ma­tio­nen aus der Datenbank zu ziehen. Nehmen wir an, Sie haben nicht nur bi­blio­gra­fi­sche Daten in Ihrem Index hin­ter­legt, sondern auch den kom­plet­ten Text jedes auf­ge­nom­me­nen Romans. Auch dieser würde bei einer einfachen GET-Anfrage mit­an­ge­zeigt. Nehmen wir aber an, Sie in­ter­es­sie­ren sich momentan nur für den Namen des Autors und den Titel des Werkes – dann können Sie auch gezielt nur danach fragen:

GET bibliography/novels/1?_source=author,title

Wenn Sie die Metadaten eines Eintrags nicht in­ter­es­sie­ren, können Sie sich auch nur den Inhalt anzeigen lassen:

GET bibliography/novels/1/_source

Nehmen wir an, Sie möchten nicht nur einen einzelnen Eintrag in Ihrem Index aufrufen, sondern gleich mehrere. Ela­s­tic­se­arch hat hierfür den _mget-Endpoint (für multi-get) im­ple­men­tiert. Wenn Sie diesen nutzen, geben Sie ein Array aus mehreren IDs an:

GET bibliography/novels/_mget
{
    "ids": ["1", "2", "3"]
}

Auch wenn ein Eintrag noch nicht besteht, läuft nicht die komplette Anfrage fehl. Denn alle be­stehen­den Daten werden Ihnen angezeigt. Was die nicht vor­han­de­nen Daten betrifft, gibt Ela­s­tic­se­arch die Rück­mel­dung, diese nicht finden zu können.

Ganz ähnlich wie der Aufruf eines Eintrags funk­tio­niert auch dessen Löschung. Statt mit GET arbeiten Sie al­ler­dings mit DELETE:

DELETE /bibliography/novels/1

Im folgenden Output gibt Ela­s­tic­se­arch Ihnen bekannt, dass es den Eintrag unter der an­ge­ge­be­nen ID gefunden hat:

{
    "_index": "bibliography",
    "_type": "novels",
    "_id": "1",
    "_version": 5,
    "result": "deleted",
}

Außerdem erhöht das Programm die Ver­si­ons­num­mer um eins. Dies hat zwei Gründe:

  1. Ela­s­tic­se­arch markiert den Eintrag nur als gelöscht und entfernt diesen nicht direkt von der Fest­plat­te. Erst im weiteren Verlauf der In­de­xie­rung wird der Eintrag ver­schwin­den.
     
  2. Wenn man mit ver­teil­ten Indexen auf mehreren Knoten arbeitet, ist eine de­tail­lier­te Ver­si­ons­ver­wal­tung äußerst wichtig. Deshalb markiert Ela­s­tic­se­arch jede Änderung als neue Version – somit auch den Lösch­auf­trag.

Sie können Än­de­run­gen auch nur an einer be­stimm­ten, Ihnen bekannten Ver­si­ons­num­mer durch­füh­ren. Sollte es im Cluster bereits eine neuere als die von Ihnen an­ge­ge­be­ne Version geben, führt der Än­de­rungs­ver­such zu einer Feh­ler­mel­dung.

PUT bibliography/novels/1?version=3
{
"author": "Marcel Proust",
"title": " À la recherche du temps perdu",
"year": "1927"
}

Sie können zudem nicht nur gleich mehrere Einträge auf einmal aufrufen, sondern mit _bulk-Aufträgen auch mehrere erstellen oder löschen. Hierfür verwendet Ela­s­tic­se­arch eine etwas ab­ge­wan­del­te Syntax.

POST bibliography/novels/_bulk
{"delete": {"_id": "1"}}
{"create": {"_id": "1"}}
{"author": "Johann Wolfgang von Goethe", "title": "Die Leiden des jungen Werther", "year": "1774"}
{"create": {"_id": "2"}}
{"author": "Umberto Eco", "title": "Il nome della rosa", "year": "1980"}
{"create": {"_id": "3"}}
{"author": "Margaret Atwood", "title": "The Handmaid’s Tale", "year": "1985"}

Jeder Auftrag bekommt eine eigene Zeile. Zunächst geben Sie an, welche Aktion durch­ge­führt werden soll (create, index, update, delete). Darüber hinaus geben Sie auch an, welchen Eintrag Sie erstellen wollen und an welchem Ort. Es ist mit einer solchen Bulk-Anweisung nämlich auch möglich, in mehreren Indexen zu arbeiten. Dafür würden Sie den Pfad nach POST leer lassen und jeder Aktion einen eigenen Pfad zuweisen. Beim Erstellen von Einträgen müssen Sie zudem – in einer neuen Zeile – einen request body angeben. In diesem steht der Inhalt des Eintrags. Die DELETE-Anweisung bedarf keines request bodys, da der komplette Eintrag gelöscht wird.

Bisher haben wir in den Bei­spie­len die Inhalte stets gleich angegeben – egal, um welches Feld es sich handelte: Ela­s­tic­se­arch hat alle In­for­ma­tio­nen als zu­sam­men­hän­gen­de Zei­chen­fol­ge in­ter­pre­tiert. Doch das ist nicht immer für jedes Feld ziel­füh­rend. Deshalb gibt es in Ela­s­tic­se­arch das Mapping. Dieses legt fest, wie die Al­go­rith­men eine Eingabe zu in­ter­pre­tie­ren haben. Mit folgendem Code können Sie sich anzeigen lassen, welches Mapping derzeit in Ihrem Index ein­ge­setzt wird:

GET bibliography/novels/_mapping

Alle Felder werden den Typen text und keyword zu­ge­ord­net. Ela­s­tic­se­arch kennt aber 6 Core Datatypes und noch mehr spezielle Felder. Die 6 Haupt­ty­pen sind teilweise in weitere Un­ter­ka­te­go­rien un­ter­glie­dert:

  • string: Hierunter fallen sowohl text als auch keyword. Während Keywords als exakte Über­ein­stim­mun­gen be­trach­tet werden, geht Ela­s­tic­se­arch bei einem Text davon aus, dass dieser ana­ly­siert werden muss, bevor man ihn benutzen kann.
     
  • numeric: Ela­s­tic­se­arch kennt ver­schie­de­ne Zah­len­wer­te, die sich vor allem im Umfang un­ter­schei­den. Während zum Beispiel der Typ byte Werte zwischen -128 und 127 einnehmen kann, hat man bei long einen Spielraum von -263 bis 263-1.
     
  • date: Ein Datum kann entweder ta­ges­ge­nau oder mit einer Uhrzeit dazu angegeben werden. Außerdem hat man die Mög­lich­keit, ein Datum in Form der Unixzeit anzugeben: Sekunden oder Mil­li­se­kun­den seit dem 1. 1. 1970. (siehe hierzu auch ISO 8601 für Da­tums­for­ma­te und Zeit­an­ga­ben)
     
  • boolean: Felder, die als boolean for­ma­tiert sind, können entweder einen wahren (true) oder einen falschen (false) Wert haben.
     
  • binary: In solchen Feldern können Sie Bi­när­da­ten un­ter­brin­gen. Um diese zu über­mit­teln, verwenden Sie die Base64-Kodierung.
     
  • range: So geben Sie einen Bereich an. Dieser kann entweder zwischen zwei Zah­len­wer­ten, zwei Daten oder sogar zwischen zwei IP-Adressen liegen.

Dies sind nur die Haupt­ka­te­go­rien, die Sie wahr­schein­lich am häu­figs­ten nutzen werden. Weitere Typen finden Sie in der Ela­s­tic­se­arch-Do­ku­men­ta­ti­on. Die einzelnen Typen un­ter­schei­den sich vor allem auch da­hin­ge­hend, dass sie entweder exact-value oder full-text sind. Ela­s­tic­se­arch versteht den Inhalt des Feldes also entweder als eine genau Eingabe oder einen Inhalt, der erst ver­ar­bei­tet werden muss. Im Zuge des Mappings ist nämlich auch das Analyzing wichtig: Das Ana­ly­sie­ren eines Inhalts un­ter­glie­dert sich wiederum in To­ke­ni­zing und Nor­ma­li­sing:

  • To­ke­ni­zing: Aus einem Text werden einzelne Tokens gemacht. Diese können einzelne Wörter, aber auch fest­ste­hen­de Begriffe aus mehreren Wörtern umfassen.
     
  • Nor­ma­li­zing: Die Tokens werden nor­ma­li­siert, indem sie alle klein­ge­schrie­ben und auf ihre Stamm­for­men reduziert werden.

Um diesen Vorgang durch­zu­füh­ren, nutzt Ela­s­tic­se­arch Analyzers. Wenn Sie ein Dokument in den Index aufnehmen und Ihr Mapping korrekt durch­ge­führt haben, werden alle Inhalte richtig in den in­ver­tier­ten Index auf­ge­nom­men. Damit Sie Mapping für sich nutzen können, müssen Sie einen komplett neuen Index erzeugen. Das Mapping von bereits exis­tie­ren­den Feldern ist nicht möglich.

PUT bibliography
{
    "mappings": {
        "novels": {
            "properties": {
                "author": {
                    "type": "text",
                    "analyzer": "simple"
                },
                "title": {
                    "type": "text",
                    "analyzer": "standard"
                },
                "year": {
                    "type": "date",
                    "format": "year"
                }
            }
        }
}
}

Die beiden Felder author und title haben wir jeweils als text und damit als full-text definiert. Daher benötigen diese noch einen passenden Analyzer. Während wir dem Feld für den Ro­man­ti­tel den Standard Analyzer zur Verfügung stellen, ent­schei­den wir uns beim Au­toren­na­men für den weniger komplexen Simple Analyzer. Das Er­schei­nungs­jahr hingegen legen wir als date – und somit als exact-value – fest. Da Ela­s­tic­se­arch als Stan­dard­for­mat eine Angabe von Jahr, Monat und Tag annimmt, ändern wir das noch, da wir uns bei der Angabe nur auf das Jahr be­schrän­ken möchten.

Suche

Im vor­an­ge­gan­ge­nen Kapitel haben wir Ela­s­tic­se­arch und dessen Index vor allem als Datenbank genutzt. Der ei­gent­li­che Nutzen von Ela­s­tic­se­arch steckt al­ler­dings in der Voll­text­su­che. Das heißt: Statt die ID eines Dokuments ein­zu­ge­ben und so den Eintrag auf­zu­ru­fen, stellen wir Ela­s­tic­se­arch nun so ein, dass Sie konkret nach Inhalten suchen können. Zur Nutzung der Such­ma­schi­ne hat das Programm den _search-Endpoint vor­ge­se­hen. Mit diesem in Kom­bi­na­ti­on mit der GET-Methode können Sie sich zum Beispiel alle Einträge anzeigen lassen:

GET bibliography/novels/_search
Fakt

Für kom­ple­xe­re Such­an­fra­gen verwendet _search einen Body in ge­schweif­ten Klammern. Einige HTTP-Server sehen dies aber für die Methode GET nicht vor. Deshalb haben sich die Ent­wick­ler ent­schie­den, dass solche Anfragen auch als POST funk­tio­nie­ren.

Sie können den Pfad auch frei lassen, um alle vor­han­de­nen Indexe zu durch­su­chen. Im Output finden Sie die in­ter­es­san­ten In­for­ma­tio­nen unter hits:

"hits": {
    "total": 3,
    "max_score": 1,
    "hits": [
        {
            "_index": "bibliography",
            "_type": "novels",
            "_id": "2",
            "_score": 1,
            "_source": {
                "author": "Umberto Eco",
                "title": "Il nome della rosa",
                "year": "1980"
            }
        },
    ],
    }
}

Auch alle weiteren Einträge in unserem Index werden im Output auf­ge­führt (und nur der Übersicht halber an dieser Stelle aus­ge­las­sen). Die Rück­mel­dung von Ela­s­tic­se­arch liefert uns neben den ei­gent­li­chen Inhalten auch zwei weitere In­for­ma­tio­nen, die uns beim Ver­ständ­nis der Voll­text­su­che helfen können:

  • hits: Jeder Eintrag, der den Such­kri­te­ri­en ent­spricht, wird von Ela­s­tic­se­arch als Treffer gewertet. Das Programm zeigt zudem die Anzahl der hits an. Da sich in unserem Beispiel 3 Einträge im Index befinden und wir uns alle anzeigen lassen, gilt "total": 3.
     
  • score: In Form einer Punktzahl gibt Ela­s­tic­se­arch an, wie relevant der Eintrag in Bezug auf unsere Such­an­fra­ge ist. Da wir in unserem Beispiel einfach nach allen Beiträgen gesucht habe, besitzen auch alle den gleichen score von 1. Die Einträge werden in den Such­ergeb­nis­sen ab­stei­gend nach der Relevanz sortiert.

Darüber hinaus liefert Ela­s­tic­se­arch in der Rück­mel­dung noch In­for­ma­tio­nen, wie viele Shards in den Such­ergeb­nis­sen in­vol­viert sind, wie viele Mil­li­se­kun­den die Suche gedauert hat und ob es zu einem Timeout gekommen ist.

Ela­s­tic­se­arch zeigt Ihnen stan­dard­mä­ßig nur die ersten 10 Such­ergeb­nis­se an. Sie können dies al­ler­dings über die Ein­stel­lung von Pa­ra­me­tern be­ein­flus­sen:

  • size: Wie viele Er­geb­nis­se soll Ela­s­tic­se­arch anzeigen?
     
  • from: Wie viele Einträge soll das Programm über­sprin­gen, bevor es welche anzeigt?

Wenn Sie nun die ersten 10 Such­ergeb­nis­se gesehen hätten und sich nur noch die folgenden 15 anzeigen lassen möchten, müssen Sie eine Kom­bi­na­ti­on aus beiden Pa­ra­me­tern verwenden:

GET bibliography/novels/_search?size=15&from=10

Ela­s­tic­se­arch un­ter­schei­det zwei ver­schie­de­ne Sucharten. Zum einen nutzt es eine Lite-Version und zum anderen eine kom­ple­xe­re Variante, die mit der Query DSL arbeitet – einer spe­zi­fi­schen Such­spra­che. Bei der Lite-Version geben Sie Ihre Such­an­fra­ge als einfachen String direkt in die Such­an­fra­ge ein:

GET bibliography/novels/_search?q=atwood

Sie können aber auch nur innerhalb eines be­stimm­ten Feldes suchen:

GET bibliography/novels/_search?q=author:atwood
Fakt

Tat­säch­lich suchen Sie auch im ersten Beispiel in einem be­stimm­ten Feld, ohne dieses angeben zu müssen: dem _all-Feld. Wenn Sie die Inhalte eines Dokuments in Felder sortiert in den Index einfügen, erzeugt Ela­s­tic­se­arch im Hin­ter­grund ein zu­sätz­li­ches Feld. In diesem sind alle Inhalte aus den anderen Feldern zu­sätz­lich ge­spei­chert, um eine solche Suche innerhalb aller Felder zu er­mög­li­chen.

Wenn Sie mehrere Such­kri­te­ri­en mit­ein­an­der kom­bi­nie­ren möchten, nutzen Sie dafür +. Mit dem Zeichen - schließen Sie bestimmte Kriterien aus. Wenn Sie diese Ope­ra­to­ren verwenden, müssen Sie in der Such­an­fra­ge al­ler­dings eine Pro­zent­ko­die­rung anwenden:

GET bibliography/novels/_search?q=%2Bauthor%3Aatwood+%2Btitle%3Ahandmaid

Die Query-String-Syntax von Ela­s­tic­se­arch bietet noch mehr Fein­hei­ten, mit denen Sie Ihre Suche anpassen können. In der Do­ku­men­ta­ti­on der Software haben die Ent­wick­ler von Elastic alles We­sent­li­che zu­sam­men­ge­fasst: Oder-Ver­knüp­fun­gen, exakte Phrasen, leere Felder oder auch Platz­hal­ter.

Für einfache Anfragen ist diese Such­va­ri­an­te gut geeignet, aber bei kom­ple­xe­ren Aufgaben kann das Lite-Verfahren schnell versagen: Zu groß ist die Gefahr, einen Fehler in den langen String ein­zu­tra­gen. Deshalb bietet Ela­s­tic­se­arch mit Query DSL ein be­que­me­res Verfahren. Der Aus­gangs­punkt einer solchen Suche ist der query-Parameter in Kom­bi­na­ti­on mit einem match query:

GET bibliography/novels/_search
{
    "query": {
        "match": {
"author": "allende"
}
    }
}

Das Ergebnis zeigt uns alle Einträge, die im author-Feld den Begriff „allende“ enthalten. An ihm erkennen wir auch, dass das Analyzing im Mapping funk­tio­niert hat, denn Ela­s­tic­se­arch ignoriert Groß- und Klein­schrei­bung. Um sich alle Einträge anzeigen zu lassen, können Sie neben der einfachen, bereits vor­ge­stell­ten Variante auch match_all verwenden:

GET bibliography/novels/_search
{
    "query": {
        "match_all": {}
    }
}

Das Gegenteil dieser Suche ist match_none. Ela­s­tic­se­arch gibt Ihnen al­ler­dings auch die Mög­lich­keit, mit einem Such­be­griff in gleich mehreren Feldern zu suchen:

GET bibliography/novels/_search
{
    "query": {
        "multi_match": {
            "query": "la",
            "fields": ["author", "title"]
        }
    }
}

Um komplexe Such­auf­trä­ge zu er­mög­li­chen, können Sie auch mehrere Such­be­grif­fe mit­ein­an­der kom­bi­nie­ren und un­ter­schied­lich bewerten. So stehen Ihnen drei Ver­bind­lich­kei­ten zur Verfügung:

  • must: Der Begriff muss vorkommen.
  • must_not: Der Begriff darf nicht vorkommen.
  • should: Wenn dieser Begriff auftaucht, wird die Relevanz in den Such­ergeb­nis­sen erhöht.

In der Praxis werden Sie diese mit einer boole­schen Abfrage kom­bi­nie­ren:

GET bibliography/novels/search_
{
    "query": {
"bool": {
        "must": {
            "match": {
                "title": "la"
            }
},
        "must_not": {
            "match": {
                "title": "rabbit"
            }
        },
        "should": {
            "match": {
                "author": "allende"
            }
        }
    }
}
}

Erweitern können Sie Ihre Suche zudem noch, indem Sie einen Filter einbauen. Dadurch können Sie Kriterien festlegen, die die Such­ergeb­nis­se ein­schrän­ken:

GET bibliography/novels/search_
{
  "query": {
"bool": {
    "must": {
      "match": {
        "title": "la"
      }
},
    "filter": {
      "range": {
        "year": {
          "gte": "1950",
          "lt": "2000"
        }
      }
    }
  }
}
}

Wir haben den Filter im vor­an­ge­gan­gen Beispiel mit einem Spektrum verknüpft: Es sollen nur die Einträge angezeigt werden, die zwischen 1950 und 2000 er­schie­nen sind.

Fazit

Mit diesem Rüstzeug haben Sie alles zur Verfügung, um die Voll­text­su­che für Ihr Projekt zu im­ple­men­tie­ren. Ela­s­tic­se­arch bietet al­ler­dings noch weitere Methoden, mit denen Sie Ihre Suche ver­fei­nern und komplexer gestalten können. Mehr dazu finden Sie auf der of­fi­zi­el­len Website von Elastic. Wenn Sie die Voll­text­su­che stärker erweitern möchten, können Sie auch eigene Skripte mit anderen Sprachen wie Groovy und Clojure erstellen.

Vor- und Nachteile von Ela­s­tic­se­arch

Ela­s­tic­se­arch kann eine kraft­vol­le Voll­text­su­che sein. Man kann Ela­s­tic­se­arch ei­gent­lich nur die schlechte Umsetzung des Open-Source-Gedankens vorwerfen. Ansonsten bietet die Voll­text­su­che zahl­rei­che Vorteile – auch gegenüber dem direkten Kon­kur­ren­ten Apache Solr.

Vorteile Nachteile
Open Source Elastic als GateĀ­keeĀ­per
schnell & stabil Ā 
skaĀ­lierĀ­bar Ā 
viele vorĀ­geĀ­ferĀ­tigĀ­te Programm-Module (Analyzer, VollĀ­textĀ­suĀ­che …) Ā 
einfache Umsetzung dank Java, JSON und REST-API Ā 
flexibel & dynamisch Ā 
Zum Hauptmenü