Viele Anwendungen müssen den Benutzern die Möglichkeit geben, Suchanfragen so anzupassen, dass sie das ergänzen, was Suchanfragen allein leisten können. In diesem Kapitel lernen Sie das Filtern kennen, eine Technik, mit der man festlegen kann, dass eine Suchanfrage nur auf der Teilmenge der in einem Index enthaltenen Dokumente ausgeführt wird, die eine bestimmte Bedingung erfüllen.

Einführung in Boolesche Abfragen

Bevor Sie Filter implementieren können, müssen Sie verstehen, wie zusammengesetzte Abfragen in Elasticsearch implementiert werden.

Eine zusammengesetzte Abfrage ermöglicht es einer Anwendung, zwei oder mehr Einzelabfragen zu kombinieren, sodass diese gemeinsam ausgeführt werden und gegebenenfalls ein kombiniertes Ergebnis zurückgeben. Die Standardmethode zum Erstellen von zusammengesetzten Abfragen in Elasticsearch besteht in der Verwendung einer booleschen Abfrage.

Eine boolesche Abfrage dient als Wrapper für zwei oder mehr einzelne Abfragen oder Klauseln. Es gibt vier verschiedene Möglichkeiten, Abfragen zu kombinieren:

  • bool.mustDie Klausel muss übereinstimmen. Wenn mehrere Klauseln angegeben werden, müssen alle übereinstimmen (ähnlich einer logischen UND-Verknüpfung).
  • bool.should: Wird es ohne must verwendet, muss mindestens eine Klausel übereinstimmen (ähnlich einer logischen ODER-Verknüpfung). In Kombination mit must erhöht jede übereinstimmende Klausel den Relevanzwert des Dokuments.
  • bool.filterNur Dokumente, die der/den Klausel(n) entsprechen, werden als Suchergebniskandidaten berücksichtigt.
  • bool.must_notNur Dokumente, die nicht mit der/den Klausel(n) übereinstimmen, werden als Suchergebniskandidaten berücksichtigt.

Wie Sie wahrscheinlich aus dem oben Gesagten erraten können, sind Boolesche Abfragen recht komplex und können auf vielfältige Weise eingesetzt werden. In diesem Kapitel lernen Sie, wie Sie die in den vorherigen Kapiteln implementierte Mehrfachübereinstimmungs-Volltextsuche mit einem Filter kombinieren, der die Ergebnisse auf eine Dokumentenkategorie beschränkt. Zur Erinnerung: Der in diesem Tutorial verwendete Datensatz enthält ein Feld category , das auf sharepoint, teams oder github gesetzt werden kann.

Hinzufügen eines Filters zu einer Abfrage

Die in der Tutorial-Anwendung implementierte Mehrfachabfrage verwendet folgende Struktur:

Um einen Filter hinzuzufügen, der diese Suche auf eine bestimmte Kategorie beschränkt, muss die Abfrage wie folgt erweitert werden:

Schauen wir uns die neuen Komponenten dieser Abfrage genauer an.

Zunächst einmal wurde die multi_match -Abfrage in eine bool.must -Klausel verschoben. Die bool.must -Klausel ist üblicherweise der Ort, an dem die Basisabfrage definiert wird. Beachten Sie, dass must eine Liste von Suchanfragen akzeptiert, sodass bei Bedarf mehrere Basisabfragen kombiniert werden können.

Die Filterung wird in einem bool.filter -Abschnitt implementiert, wobei ein neuer Abfragetyp, die term -Abfrage, verwendet wird. Die Verwendung einer match oder multi_match -Abfrage als Filter ist keine gute Idee, da es sich hierbei um Volltextsuchanfragen handelt. Zum Zweck der Filterung muss die Abfrage für jedes Dokument eine absolute Wahrheit oder Falschheit zurückgeben und nicht wie die Match-Abfragen einen Relevanzwert.

Der Begriff „ Query“ führt eine exakte Suche nach dem Wert „a“ in einem gegebenen Feld durch. Diese Art von Abfrage ist nützlich, um nach Kennungen, Bezeichnungen, Tags oder, wie in diesem Fall, Kategorien zu suchen.

Diese Abfrage funktioniert nicht gut mit Feldern, die für die Volltextsuche indiziert sind. Zeichenkettenfeldern wird standardmäßig der Datentyp „Text“ zugewiesen. Ihr Inhalt wird analysiert und in einzelne Wörter zerlegt, bevor sie indexiert werden. Elasticsearch weist String-Feldern einen sekundären Typ vom Typ „keyword“ zu, der den Feldinhalt als Ganzes indiziert und sie somit besser für die Filterung mit der Abfrage term geeignet macht. Durch die Verwendung des Feldnamens category.keyword im Filterteil der Abfrage wird die typisierte Variante keyword des Feldes anstelle der Standardvariante text verwendet.

Festlegen eines Filters

Bevor die gefilterte Abfrage implementiert werden kann, muss eine Möglichkeit für Endbenutzer geschaffen werden, einen gewünschten Filter einzugeben. Die in diesem Tutorial vorgestellte Lösung sucht im Text der Suchanfrage nach dem Muster category:<category-name> . Fügen wir der Datei app.py eine Funktion namens extract_filters() hinzu, die nach Filterausdrücken sucht:

Die Funktion nimmt die vom Benutzer eingegebene Abfrage entgegen und gibt ein Tupel zurück, das die in der Abfrage gefundenen Filter und die nach dem Entfernen der Filter geänderte Abfrage enthält. Um das Filtermuster zu finden, wird ein regulärer Ausdruck verwendet. Die Funktion ist so konzipiert, dass sie mit zusätzlichen Filtern erweitert werden kann.

Wenn ein Filter gefunden wird, wird die filters -Liste um einen entsprechenden Filterausdruck erweitert, der in diesem Fall auf der term -Abfrage basiert, wie oben beschrieben.

Um besser zu verstehen, wie diese Funktion funktioniert, starten Sie eine Python-Sitzung (stellen Sie sicher, dass die virtuelle Umgebung vorher aktiviert ist) und führen Sie den folgenden Code aus:

Das von der Funktion zurückgegebene Tupel sollte wie folgt aussehen:

Implementierung der gefilterten Suche

Was noch zu tun ist, ist, die handle_search() -Funktion so zu ändern, dass sie eine aktualisierte Abfrage sendet, die den Volltextsuchausdruck mit einem Filter kombiniert, falls ein solcher vom Benutzer angegeben wurde. Nachfolgend die neue Version dieser Funktion:

Die Abfrage wurde nun so geändert, dass ein bool -Ausdruck gesendet wird, und der Suchausdruck wurde in einen darunter liegenden must -Abschnitt verschoben. Die Funktion extract_filters() gibt den Filterteil der Abfrage in der Form zurück, in der er an Elasticsearch gesendet werden muss, sodass er auch im Abfragewörterbuch unter dem Schlüssel bool der obersten Ebene eingefügt wird.

Versuchen Sie eine Suchanfrage wie work from home category:sharepoint , um zu sehen, wie nur Dokumente aus der angegebenen Kategorie zurückgegeben werden.

Bereichsfilter

Elasticsearch unterstützt neben dem term -Filter eine Vielzahl weiterer Filter. Ein weiterer häufig verwendeter Filter ist der range -Filter, der mit Zahlen und Datumsangaben funktioniert. Fügen wir einen year -Filter hinzu, mit dem die Ergebnisse auf der Grundlage des Jahres ihrer letzten Aktualisierung eingeschränkt werden können, das im Feld updated_at angegeben ist.

Nachfolgend finden Sie eine aktualisierte Version der Funktion extract_filters() , die sowohl category:<category> als year:<yyyy> als Filter berücksichtigt:

Diese Version fügt einen zweiten regulären Ausdruck hinzu, um year:yyyy in der Abfragezeichenfolge zu finden. Es erstellt einen range -Filter für das updated_at -Feld und setzt die untere und obere Grenze des Bereichs auf das Jahr, das nach dem Doppelpunkt angegeben wird und im regulären Ausdruck als m.group(1) erfasst wird.

Es gibt eine kleine Komplikation, da das Feld updated_at vollständige Datumsangaben enthält, dieser Filter aber nur das Jahr berücksichtigen muss. Zum Glück lassen sich bei Verwendung des Bereichsfilters mit einem Datumsfeld die Grenzen des Bereichs mithilfe von Datumsberechnungen erweitern. Das Suffix ||/y , das den Parametern gte (untere Grenze) und lte (obere Grenze) des Bereichs hinzugefügt wird, gibt an, dass der angegebene Wert ein Jahr ist, das vervollständigt werden muss, um ein vollständiges Datum zu bilden, das mit dem Feld verglichen werden kann.

Mit dieser Änderung können Sie eine Abfrage wie year:2020 work from home einfügen, um nur Ergebnisse aus dem angeforderten Jahr anzuzeigen. Die Abfrage kann auch die beiden Filter enthalten, zum Beispiel year:2020 category:teams work from home.

Die Match-All-Abfrage

Bevor Sie zu einem neuen Thema übergehen, versuchen Sie, nur einen Filter in das Suchfeld einzugeben, zum Beispiel category:github. Leider liefert diese Abfrage keine Ergebnisse, erwartet würde man in diesem Fall jedoch alle Ergebnisse, die der angeforderten Kategorie entsprechen.

Das Ergebnis ist, dass die Funktion extract_filters() ein Tupel zurückgibt, dessen erstes Element den/die Filter enthält und dessen zweites Element eine leere Abfragezeichenfolge ist. Die multi_match -Abfrage empfängt eine leere Zeichenkette und gibt eine leere Ergebnisliste zurück, da es keine Übereinstimmung mit einer leeren Zeichenkette gibt.

Um diesem Sonderfall zu begegnen, kann die Abfrage multi_match durch match_all ersetzt werden, wenn der Suchtext leer ist. Die untenstehende Version der handle_search() -Funktion fügt die Logik hinzu, um dies zu erreichen. Aktualisieren Sie die Funktion in app.py.

Mit dieser Version können Sie alle Dokumente anfordern, die einer Kategorie entsprechen. Beachten Sie, dass alle zurückgegebenen Ergebnisse die gleiche Punktzahl von 1,0 aufweisen, da keine Suchbegriffe zur Berechnung von Punktzahlen vorhanden sind.

Sind Sie bereit, hochmoderne Sucherlebnisse zu schaffen?

Eine ausreichend fortgeschrittene Suche kann nicht durch die Bemühungen einer einzelnen Person erreicht werden. Elasticsearch wird von Datenwissenschaftlern, ML-Ops-Experten, Ingenieuren und vielen anderen unterstützt, die genauso leidenschaftlich an der Suche interessiert sind wie Sie. Lasst uns in Kontakt treten und zusammenarbeiten, um das magische Sucherlebnis zu schaffen, das Ihnen die gewünschten Ergebnisse liefert.

Probieren Sie es selbst aus