Springデータを使用したElasticsearchクエリ

データ]

  • リンク:/tag/elasticsearch/[Elasticsearch]

1前書き

リンク:/spring-data-elasticsearch-tutorial[前の記事]では、Spring Data Elasticsearchをプロジェクト用に構成して使用する方法を説明しました。この記事ではElasticsearchが提供するいくつかのクエリタイプを検証し、フィールドアナライザとそれらが検索結果に与える影響についても説明します。

2アナライザー

デフォルトでは、格納されているすべての文字列フィールドはアナライザによって処理されます。アナライザは、1つのトークナイザと複数のトークンフィルタで構成され、通常は1つ以上の文字フィルタが先行します。

デフォルトのアナライザは、一般的な単語の区切り文字(スペースや句読点など)で文字列を分割し、すべてのトークンを小文字にします。一般的な英語の単語も無視されます。

Elasticsearchは、フィールドを分析済みと未分析の両方と見なすように構成することもできます。

たとえば、 Article クラスで、titleフィールドを標準の分析済みフィールドとして格納するとします。接尾辞 verbatim を持つ同じフィールドは、未分析フィールドとして保存されます。

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

ここでは、 @ MultiField アノテーションを適用して、このフィールドにいくつかの方法でインデックスを付けたいことをSpring Dataに伝えます。メインフィールドは title という名前を使用し、上記の規則に従って分析されます。

しかし、 title フィールドの追加のインデックス付けを記述する @ InnerField という2番目のアノテーションもあります。 FieldType.keyword を使用して、フィールドの追加のインデックス作成を実行するときにアナライザーを使用したくないこと、およびこの値は接尾辞 verbatim を持つネストしたフィールドを使用して格納する必要があることを示します。

2.1. 分析フィールド

例を見てみましょう。 「Spring Data Elasticsearch」というタイトルの記事がインデックスに追加されたとします。デフォルトのアナライザは、スペース文字で文字列を分割し、小文字のトークンを生成します。

スプリング ”、“データ _”、 および“ elasticsearch_

今度は私達は文書を一致させるのにこれらの言葉のあらゆる組合せを使用するかもしれない:

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

2.2. 未解析分野

分析されていないフィールドはトークン化されていないため、matchクエリまたはtermクエリを使用した場合は、全体としてしか照合できません。

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

一致クエリを使用して、完全なタイトルでのみ検索できます。これも大文字と小文字を区別します。

3一致クエリ

  • match query ** はテキスト、数字、そして日付を受け付けます。

「match」クエリには3種類あります。

  • ブール値

  • and

  • phrase prefix __

このセクションでは、 boolean matchクエリについて調べます。

3.1. ブール演算子とのマッチング

boolean は、一致クエリのデフォルトタイプです。使用するブール演算子を指定できます( or がデフォルト)。

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

このクエリは、タイトルから2つの用語を and 演算子で指定することによって、タイトルが "Search engines"の記事を返します。しかし、一方の語のみが一致したときにデフォルトの( or )演算子を使用して検索するとどうなりますか?

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

「検索エンジン__」の記事はまだ一致していますが、すべての用語が一致したわけではないため、スコアが低くなります。

一致する各用語のスコアの合計が、結果として得られる各ドキュメントの合計スコアになります。

クエリに入力されたまれな用語を含むドキュメントが、いくつかの一般的な用語を含むドキュメントよりも上位になる場合があります。

3.2. あいまいさ

ユーザーが単語をタイプミスした場合でも、 fuzziness パラメーターを指定することで検索と照合することができます。これにより、不正確な照合が可能になります。

文字列フィールドの場合、 fuzziness は編集距離を意味します。1つの文字列を他の文字列と同じにするために必要な1文字の変更数

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

prefix length__パラメータはパフォーマンスを向上させるために使用されます。この場合、最初の3文字が完全に一致する必要があります。これにより、可能な組み合わせの数が減ります。

5フレーズ検索

位相探索はより厳密ですが、 slop パラメータで制御できます。このパラメーターは、文書を一致と見なしながら、用語をどれだけ離しておくことができるかを句queryに指示します。

つまり、クエリとドキュメントを一致させるために用語を移動する必要がある回数を表します。

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

ここでは、傾きが1に設定されているため、クエリによってドキュメントとタイトル「 Spring Data Elasticsearch 」が一致します。

6. マルチマッチクエリ

複数のフィールドを検索したい場合は、 QueryBuilders#multiMatchQuery() を使用して、一致するすべてのフィールドを指定します。

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

ここでは、 title tags フィールドで一致するものを検索します。

ここでは、「ベストフィールド」スコアリング戦略を使用しています。それは、文書スコアとしてフィールド間の最大スコアを取ります。

7. 集計

Article クラスでは、分析されていない tags フィールドも定義しました。集計を使用してタグクラウドを簡単に作成できます。

フィールドは分析されていないため、タグはトークン化されません。

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<String, Aggregation> results = response.getAggregations().asMap();
StringTerms topTags = (StringTerms) results.get("top__tags");

List<String> keys = topTags.getBuckets()
  .stream()
  .map(b -> b.getKeyAsString())
  .collect(toList());
assertEquals(asList("elasticsearch", "spring data", "search engines", "tutorial"), keys);

8概要

この記事では、分析フィールドと非分析フィールドの違い、およびこの区別が検索に与える影響について説明しました。

また、一致クエリ、フレーズ一致クエリ、全文検索クエリ、ブールクエリなど、Elasticsearchによって提供されるいくつかの種類のクエリについても学びました。

Elasticsearchは、地理クエリ、スクリプトクエリ、複合クエリなど、他にも多くの種類のクエリを提供します。 Elasticsearch documentation でそれらについて読み、これらのクエリを使用するためにSpring Data Elasticsearch APIを調べることができます。あなたのコード

この記事で使われている例を含むプロジェクトはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-elasticsearch[GitHub repository]にあります。

Related