Elasticsearch-Abfragen mit Spring-Daten

Elasticsearch-Abfragen mit Federdaten

1. Einführung

Inprevious article 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. Außerdem werden Feldanalysatoren und ihre Auswirkungen auf die Suchergebnisse erläutert.

2. Analysatoren

Alle gespeicherten Zeichenfolgenfelder werden standardmäßig von einem Analysegerät verarbeitet. Ein Analysator besteht aus einem Tokenizer und mehreren Tokenfiltern. In der Regel gehen ein oder mehrere Zeichenfilter voraus.

Der Standardanalysator teilt die Zeichenfolge durch gebräuchliche 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.

Angenommen, in einerArticle-Klasse wird das Titelfeld als standardmäßiges analysiertes Feld gespeichert. Das gleiche Feld mit dem Suffixverbatim 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@MultiFieldan, um Spring Data mitzuteilen, dass dieses Feld auf verschiedene Arten indiziert werden soll. Das Hauptfeld verwendet den Namentitle und wird gemäß den oben beschriebenen Regeln analysiert.

Wir stellen aber auch eine zweite Annotation bereit,@InnerField, die eine zusätzliche Indizierung des Feldstitle beschreibt. Wir verwendenFieldType.keyword, um anzuzeigen, dass wir bei der zusätzlichen Indizierung des Feldes keinen Analysator verwenden möchten und dass dieser Wert unter Verwendung eines verschachtelten Felds mit dem Suffixverbatim gespeichert werden sollte.

2.1. Analysierte Felder

Schauen wir uns ein Beispiel an. Angenommen, ein Artikel mit dem Titel "Spring Data Elasticsearch" wird in unseren Index aufgenommen. Der Standardanalysator zerlegt die Zeichenfolge an den Leerzeichen und erzeugt Kleinbuchstaben: „spring“, „Daten“,“ und „elasticsearch“.

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

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

2.2. Nicht analysierte Felder

Ein nicht analysiertes Feld wird nicht mit einem Token versehen und kann nur dann als Ganzes abgeglichen werden, wenn Übereinstimmungs- oder Begriffsabfragen verwendet werden:

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

Bei einer Übereinstimmungsabfrage wird möglicherweise nur nach dem vollständigen Titel gesucht, bei dem auch die Groß- und Kleinschreibung beachtet wird.

3. Abfrage abgleichen

Amatch query akzeptiert Text, Zahlen und Daten.

Es gibt drei Arten von Übereinstimmungsabfragen:

  • Boolescher Wert

  • phrase und

  • phrasenpräfix

In diesem Abschnitt werden wir die Übereinstimmungsabfrage vonbooleanuntersuchen.

3.1. Matching mit Booleschen Operatoren

boolean ist der Standardtyp einer Übereinstimmungsabfrage. Sie können angeben, welcher boolesche Operator verwendet werden soll (or ist Standard):

SearchQuery searchQuery = new NativeSearchQueryBuilder()
  .withQuery(matchQuery("title","Search engines").operator(AND))
  .build();
List
articles = getElasticsearchTemplate() .queryForList(searchQuery, Article.class);

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

SearchQuery searchQuery = new NativeSearchQueryBuilder()
  .withQuery(matchQuery("title", "Engines Solutions"))
  .build();
List
articles = getElasticsearchTemplate() .queryForList(searchQuery, Article.class); assertEquals(1, articles.size()); assertEquals("Search engines", articles.get(0).getTitle());

Der Artikel "Search engines" 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 in die Abfrage eingegebenen seltenen Begriff enthält, einen höheren Rang hat als ein Dokument, das mehrere gebräuchliche 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 einfuzziness-Parameter angegeben wird, der eine ungenaue Übereinstimmung ermöglicht.

Für Zeichenfolgenfelder bedeutetfuzziness den Bearbeitungsabstand: Die Anzahl der einstelligen Änderungen, die an einer Zeichenfolge vorgenommen werden müssen, damit sie mit einer anderen Zeichenfolge identisch ist.

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

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

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

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

SearchQuery 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 SieQueryBuilders#multiMatchQuery() verwenden, in denen Sie alle Felder angeben, die übereinstimmen:

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

Hier durchsuchen wir die Feldertitle undtags nach einer Übereinstimmung.

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

7. Aggregationen

In unsererArticle-Klasse haben wir auch eintags-Feld definiert, das nicht analysiert wird. Mithilfe einer Aggregation können wir leicht eine Tag-Cloud erstellen.

Beachten Sie, dass die Tags nicht mit einem Token versehen werden, da das Feld nicht analysiert wird:

TermsAggregationBuilder aggregation = AggregationBuilders.terms("top_tags")
  .field("tags")
  .order(Terms.Order.count(false));
SearchResponse response = client.prepareSearch("blog")
  .setTypes("article")
  .addAggregation(aggregation)
  .execute().actionGet();

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. Zusammenfassung

In diesem Artikel haben wir den Unterschied zwischen analysierten und nicht analysierten Feldern erörtert und wie sich diese Unterscheidung auf die Suche auswirkt.

Wir haben auch einige Arten von Abfragen kennengelernt, die von Elasticsearch bereitgestellt werden, z. B. die Übereinstimmungsabfrage, die Phrasenübereinstimmungsabfrage, die Volltextsuchabfrage und die Boolesche Abfrage.

Elasticsearch bietet viele andere Arten von Abfragen, z. B. Geo-Abfragen, Skriptabfragen und zusammengesetzte Abfragen. Sie können sie inElasticsearch documentationlesen und die Spring Data Elasticsearch-API durchsuchen, um diese Abfragen in Ihrem Code zu verwenden.

Sie finden ein Projekt mit den in diesem Artikel verwendeten Beispielen inthe GitHub repository.