Nicht einfach von Stack Overflow kopieren, sondern verstehen, was man kopiert.
Elasticsearch ist heutzutage die Suchmaschine schlechthin, aber seine Query DSL hat eine steile Lernkurve. Als ich anfing, Elasticsearch-Abfragen zu schreiben, konnte ich durch eine Kombination aus den Elastic.co-Dokumenten und Stack Overflow etwas zusammenstellen, das funktionierte, aber ich verstand die zugrundeliegenden Konzepte hinter der Syntax nicht vollständig.
Dieses Tutorial zielt darauf ab, das zu sein, was ich gerne zuerst gelesen hätte. Es setzt voraus, dass der Leser mit den grundlegenden Konzepten von Elasticsearch vertraut ist, einfache Abfragen schreiben kann und boolesche Logik versteht. Es zielt darauf ab, dem Leser eine solide konzeptionelle Basis von Elasticsearch zu geben, bevor er versucht, die Syntax zu verstehen.
Filtern nach exakten Werten vs. volltextanalytische Suche
Ein übergreifendes Thema in Elasticsearch ist, dass alle Abfragen in drei Typen klassifiziert werden können:
1. Filtern nach exakten Werten
2. Suchen auf analysiertem Text
3. Eine Kombination aus beiden
Jedes Dokumentenfeld kann entweder als exakte Werte oder als analysierter Text (auch Volltext genannt) klassifiziert werden. Exakte Werte sind Felder wie user_id
date
email_addresses
, usw. Analysierter Text sind Textdaten wie product_description
oder email_body
. Wie der Name schon sagt, sind diese Textdaten analysiert worden (mehr dazu später). Sie sind oft in einer natürlichen Sprache verfasst, aber nicht notwendigerweise.
Die Abfrage von Dokumenten kann durch die Angabe von Filtern über genaue Werte erfolgen. In diesen Fällen ist die Frage, ob das Dokument zurückgegeben wird, ein binäres Ja oder Nein. Ist zum Beispiel das user_id
des Dokuments gleich 174517
? Liegt das created_at
Datum des Dokuments im Bereich des letzten Monats?
Auf der anderen Seite gibt die Abfrage von Dokumenten durch die Suche nach analysiertem Text Ergebnisse basierend auf Relevanz zurück. Ein Dokument wird nicht nach einem Ja/Nein-Kriterium zurückgegeben, sondern danach, wie relevant es ist. Wenn der analysierte Text eines Dokuments z. B. Johnny Depp enthält, sollte es auch bei Suchen nach John Depp oder Johnnie Depp zurückgegeben werden. Eine Suche nach „cook“ sollte auch Ergebnisse für „cooking“ und „cooked“ liefern.
Aus diesem Verhalten lässt sich ableiten, dass die Suche nach analysiertem Text eine hochkomplexe Operation ist und je nach Art der Textdaten unterschiedliche Analyzer-Pakete verwendet werden. Zum Beispiel sind einige Analysatorpakete sprachspezifisch, die für die Analyse von Text in einer bestimmten Sprache verwendet werden. Das Standard-Analysatorpaket ist der Standard-Analysator, der den Text nach Wortgrenzen aufteilt, Kleinbuchstaben und Interpunktion entfernt. Da die Suche nach analysiertem Text sehr viel komplizierter ist als das Filtern nach exakten Werten, ist sie sehr viel weniger performant als das Filtern nach exakten Werten. Wir werden die Suche nach analysiertem Text kurz als analysierte Suche bezeichnen.
Die Abfrage-DSL
Elasticsearch-Abfragen bestehen aus einer oder mehreren Abfrageklauseln. Abfrageklauseln können kombiniert werden, um andere Abfrageklauseln zu erstellen, die sogenannten zusammengesetzten Abfrageklauseln. Alle Abfrageklauseln haben eines dieser beiden Formate:
{
QUERY_CLAUSE: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}{
QUERY_CLAUSE: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
Die Syntax-Regel besagt, dass Abfrageklauseln wiederholt in anderen Abfrageklauseln verschachtelt werden können
{
QUERY_CLAUSE {
QUERY_CLAUSE: {
QUERY_CLAUSE: {
QUERY_CLAUSE: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
}
}
Hier sind einige gängige Abfrageklauseln.
Match-Abfrageklausel
Die Match-Abfrageklausel ist die allgemeinste und am häufigsten verwendete Abfrageklausel. Sie ist ziemlich intelligent, denn wenn sie auf einem analysierten Textfeld ausgeführt wird, führt sie eine analysierte Suche auf dem Text durch. Wenn sie auf ein Feld mit einem exakten Wert ausgeführt wird, führt sie einen Filter durch.
Im folgenden Beispiel führt die erste Abfrageklausel eine analysierte Suche durch, da description
ein analysiertes Textfeld ist. Während die zweiten beiden Abfragen Filter über exakte Wertfelder sind.
{ "match": { "description": "Fourier analysis signals processing" }}
{ "match": { "date": "2014-09-01" }}
{ "match": { "visible": true }}
Die Match-All-Abfrageklausel
Die Match-All-Abfrageklausel gibt alle Dokumente zurück. Sie ist analog zu SELECT * FROM table
in SQL.
{ "match_all": {} }
Term/Terms Abfrageklausel
Die Term- und Term-Abfrageklauseln werden verwendet, um nach einem exakten Wertefeld nach einzelnen bzw. mehreren Werten zu filtern. Bei mehreren Werten lautet die logische Verknüpfung OR
.
Beispielsweise findet die erste Abfrage alle Dokumente mit dem Tag „math“. Die zweite Abfrage findet alle Dokumente mit den Tags „math“ oder „statistics“.
{ "term": { "tag": "math" }}
{ "terms": { "tag": }}
Multi-Match-Abfrageklausel
Die Multi-Match-Abfrageklausel ist eine Abgleichsabfrage, die über mehrere Felder anstelle von nur einem ausgeführt wird.
{
"multi_match": {
"query": "probability theory",
"fields":
}
}
Exists- und Missing-Filter Abfrageklausel
Der exists-Filter prüft, ob Dokumente einen Wert in einem bestimmten Feld haben. Der Missing-Filter prüft, dass Dokumente keinen Wert an einem bestimmten Feld haben. Sie sind analog zu den SQL-Klauseln IS NULL
und IS NOT NULL
.
{
"exists" : {
"field" : "title"
}
}
und
{
"missing" : {
"field" : "title"
}
}
Range-Filter-Abfrageklausel
Die Range-Filter-Abfrageklausel wird verwendet, um Zahlen- und Datumsfelder in Bereichen zu filtern, unter Verwendung der Operatoren gt
gte
lt
lte
kurz für greater_than
greater_than_or_equal
less_than
und less_than_or_equal
, beziehungsweise.
{ "range" : { "age" : { "gt" : 30 } } }{
"range": {
"born" : {
"gte": "01/01/2012",
"lte": "2013",
"format": "dd/MM/yyyy||yyyy"
}
}
}
Boolsche Abfrageklausel
Abfrageklauseln, die aus anderen Abfrageklauseln aufgebaut sind, werden zusammengesetzte Abfrageklauseln genannt. Beachten Sie, dass zusammengesetzte Abfrageklauseln auch aus anderen zusammengesetzten Abfrageklauseln bestehen können, was eine mehrschichtige Verschachtelung ermöglicht.
Die bool-Abfrageklausel ist ein Beispiel für eine zusammengesetzte Abfrageklausel, da sie verwendet wird, um mehrere Abfrageklauseln mit boolschen Operatoren zu kombinieren. Die drei unterstützten boolschen Operatoren sind must
must_not
und should
, die jeweils AND
NOT
, und OR
entsprechen.
Angenommen, wir haben einen Index auf dem posts
einer beliebten Social-Media-Seite. Hier ist eine Abfrage, um alle posts
über Mathematik zu finden, die nicht wahrscheinlich ist, wo sie entweder ungelesen ist oder favorisiert wurde.
{
"bool": {
"must": { "term": { "tag": "math" }},
"must_not": { "term": { "tag": "probability" }},
"should":
}
}
Kombinieren von analysierter Suche mit Filtern
Wir haben über exakte Feldfilter und analysierte Suche in getrennten Kontexten gesprochen, aber in realen Anwendungen wollen wir die beiden oft kombinieren. Wir kombinieren analysierte Suche und exakte Feldfilter mit Hilfe der Filterklausel.
Angenommen, wir haben einen Index auf dem posts
eines beliebten Webforums über Mathematik. Hier ist eine Abfrage, um alle Beiträge zu finden, indem wir eine analysierte Suche nach „Wahrscheinlichkeitstheorie“ durchführen, aber wir wollen nur posts
mit 20 oder mehr Bewertungen und nicht die mit dem Tag „frequentist“.
{
"filtered": {
"query": { "match": { "body": "Probability Theory" }},
"filter": {
"bool": {
"must": {
"range": { "upvotes" : { "gt" : 20 } }
},
"must_not": { "term": { "tag": "frequentist" } }
}
}
}
}
Zusammenfassung
Der konzeptionelle Hintergrund der Elasticsearch-Abfrage-DSL ist diese Dichotomie des Filterns von Dokumenten gegenüber der Suche durch analysierten Text. Ich hoffe, Sie fanden das hilfreich.