Elasticsearch-Abfragen mit Federdaten

1. Einleitung

In einem früheren Artikel haben wir gezeigt, wie Spring Data Elasticsearch für ein Projekt konfiguriert und verwendet wird. In diesem Artikel werden verschiedene von Elasticsearch angebotene Abfragetypen untersucht und Feldanalysatoren und ihre Auswirkungen auf die Suchergebnisse erläutert.

2. Analysatoren

Alle gespeicherten Zeichenfolgenfelder werden standardmäßig von einem Analysator verarbeitet. Ein Analysator besteht aus einem Tokenizer und mehreren Tokenfiltern und wird normalerweise von einem oder mehreren Zeichenfiltern vorangestellt.

Der Standardanalysator teilt die Zeichenfolge durch allgemeine Worttrennzeichen (z. B. Leerzeichen oder Interpunktion) auf und setzt jedes Token in Kleinbuchstaben. Es ignoriert auch gebräuchliche englische Wörter.

Elasticsearch kann auch so konfiguriert werden, dass ein Feld gleichzeitig als analysiert und nicht analysiert betrachtet wird.

Zum Beispiel in einem Artikel Klasse an , dass wir den Titel Feld speichern , wie ein Standardfeld analysiert. Das gleiche Feld mit dem Suffix wörtlich wird als nicht analysiertes Feld gespeichert:

@MultiField( mainField = @Field(type = Text, fielddata = true), otherFields = { @InnerField(suffix = "verbatim", type = Keyword) } ) private String title;

Hier wenden wir die Annotation @MultiField an, um Spring Data mitzuteilen, dass dieses Feld auf verschiedene Arten indiziert werden soll. Das Hauptfeld verwendet den Namenstitel und wird gemäß den oben beschriebenen Regeln analysiert.

Aber wir bieten auch eine zweite Anmerkung, @InnerField , die eine zusätzliche Indizierung des beschreibt Titelfeld. Wir verwenden FieldType.keyword, um anzugeben, dass wir bei der zusätzlichen Indizierung des Felds keinen Analysator verwenden möchten und dass dieser Wert unter Verwendung eines verschachtelten Felds mit dem wörtlichen Suffix gespeichert werden sollte .

2.1. Analysierte Felder

Schauen wir uns ein Beispiel an. Angenommen, ein Artikel mit dem Titel "Spring Data Elasticsearch" wird unserem Index hinzugefügt. Der Standardanalysator zerlegt die Zeichenfolge an den Leerzeichen und erzeugt Kleinbuchstaben: " spring ", " data" und " elasticsearch ".

Jetzt können wir eine beliebige Kombination dieser Begriffe verwenden, um ein Dokument abzugleichen:

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery("title", "elasticsearch data")) .build();

2.2. Nicht analysierte Felder

Ein nicht analysiertes Feld ist nicht tokenisiert und kann daher nur als Ganzes abgeglichen werden, wenn Übereinstimmungs- oder Termabfragen verwendet werden:

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery("title.verbatim", "Second Article About Elasticsearch")) .build();

Bei Verwendung einer Übereinstimmungsabfrage wird möglicherweise nur nach dem vollständigen Titel gesucht, wobei auch zwischen Groß- und Kleinschreibung unterschieden wird.

3. Abfrage abgleichen

Eine Übereinstimmungsabfrage akzeptiert Text, Zahlen und Daten.

Es gibt drei Arten von Übereinstimmungsabfragen:

  • Boolescher Wert
  • Phrase und
  • phrasenpräfix

In diesem Abschnitt werden wir die boolesche Übereinstimmungsabfrage untersuchen.

3.1. Matching mit Booleschen Operatoren

Boolescher Wert ist der Standardtyp einer Übereinstimmungsabfrage. Sie können angeben, welcher boolesche Operator verwendet werden soll ( oder der Standardoperator ist):

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery("title","Search engines").operator(Operator.AND)) .build(); SearchHits articles = elasticsearchTemplate() .search(searchQuery, Article.class, IndexCoordinates.of("blog"));

Diese Abfrage würde einen Artikel mit dem Titel "Suchmaschinen" zurückgeben, indem zwei Begriffe aus dem Titel mit und Operator angegeben werden. Aber was passiert, wenn wir mit dem Standardoperator ( oder ) suchen, wenn nur einer der Begriffe übereinstimmt?

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery("title", "Engines Solutions")) .build(); SearchHits articles = elasticsearchTemplate() .search(searchQuery, Article.class, IndexCoordinates.of("blog")); assertEquals(1, articles.getTotalHits()); assertEquals("Search engines", articles.getSearchHit(0).getContent().getTitle());

Der Artikel " Suchmaschinen " stimmt immer noch überein, hat jedoch eine niedrigere Punktzahl, da nicht alle Begriffe übereinstimmen.

Die Summe der Bewertungen jedes übereinstimmenden Begriffs ergibt die Gesamtbewertung jedes resultierenden Dokuments.

Es kann Situationen geben, in denen ein Dokument, das einen seltenen Begriff enthält, der in die Abfrage eingegeben wurde, einen höheren Rang hat als ein Dokument, das mehrere allgemeine Begriffe enthält.

3.2. Unschärfe

Wenn der Benutzer einen Tippfehler in einem Wort macht, ist es weiterhin möglich, ihn mit einer Suche abzugleichen , indem ein Unschärfeparameter angegeben wird, der eine ungenaue Übereinstimmung ermöglicht.

Für Zeichenfolgenfelder bedeutet Unschärfe den Bearbeitungsabstand: Die Anzahl der Änderungen an einem Zeichen, die an einer Zeichenfolge vorgenommen werden müssen, damit sie mit einer anderen Zeichenfolge identisch ist.

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery("title", "spring date elasticsearch") .operator(Operator.AND) .fuzziness(Fuzziness.ONE) .prefixLength(3)) .build();

Der Parameter prefix_length wird verwendet, um die Leistung zu verbessern. In diesem Fall müssen die ersten drei Zeichen genau übereinstimmen, wodurch sich die Anzahl der möglichen Kombinationen verringert.

5. Phrasensuche

Die Phasensuche ist strenger, obwohl Sie sie mit dem Parameter slop steuern können . Dieser Parameter teilt der Phrasenabfrage mit, wie weit die Begriffe voneinander entfernt sein dürfen, während das Dokument dennoch als übereinstimmend betrachtet wird.

Mit anderen Worten, es gibt an, wie oft Sie einen Begriff verschieben müssen, damit Abfrage und Dokument übereinstimmen:

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchPhraseQuery("title", "spring elasticsearch").slop(1)) .build();

Hier wird die Abfrage dem Dokument mit dem Titel " Spring Data Elasticsearch " zugeordnet, da wir den Slop auf eins setzen.

6. Multi-Match-Abfrage

Wenn Sie in mehreren Feldern suchen möchten, können Sie QueryBuilders # multiMatchQuery () verwenden, in dem Sie alle Felder angeben, die übereinstimmen:

NativeSearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(multiMatchQuery("tutorial") .field("title") .field("tags") .type(MultiMatchQueryBuilder.Type.BEST_FIELDS)) .build();

Hier durchsuchen wir die Titel- und Tag- Felder nach einer Übereinstimmung.

Beachten Sie, dass wir hier die Bewertungsstrategie „Beste Felder“ verwenden. Es wird die maximale Punktzahl unter den Feldern als Dokumentpunktzahl verwendet.

7. Aggregationen

In our Article class we have also defined a tags field, which is non-analyzed. We could easily create a tag cloud by using an aggregation.

Remember that, because the field is non-analyzed, the tags will not be tokenized:

TermsAggregationBuilder aggregation = AggregationBuilders.terms("top_tags") .field("tags") .order(Terms.Order.count(false)); SearchSourceBuilder builder = new SearchSourceBuilder().aggregation(aggregation); SearchRequest searchRequest = new SearchRequest().indices("blog").types("article").source(builder); SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); Map results = response.getAggregations().asMap(); StringTerms topTags = (StringTerms) results.get("top_tags"); List keys = topTags.getBuckets() .stream() .map(b -> b.getKeyAsString()) .collect(toList()); assertEquals(asList("elasticsearch", "spring data", "search engines", "tutorial"), keys);

8. Summary

In this article, we discussed the difference between analyzed and non-analyzed fields, and how this distinction affects search.

We also learned about several types of queries provided by Elasticsearch, such as the match query, phrase match query, full-text search query, and boolean query.

Elasticsearch provides many other types of queries, such as geo queries, script queries and compound queries. You can read about them in the Elasticsearch documentation and explore the Spring Data Elasticsearch API in order to use these queries in your code.

Ein Projekt mit den in diesem Artikel verwendeten Beispielen finden Sie im GitHub-Repository.