Solrによる全文検索

1概要

この記事では、http://lucene.apache.org/solr[[Apache Solr]検索エンジン - 全文検索の基本概念を探ります。

  • Apache Solrは、何百万もの文書を扱うように設計されたオープンソースのフレームワークです** Javaライブラリーを使用した例で、その中核機能を調べます - SolrJ

2 Mavenの設定

Solrがオープンソースであるという事実を考えると、バイナリをダウンロードして、アプリケーションとは別にサーバーを起動することができます。

サーバーと通信するために、SolrJクライアントのMaven依存関係を定義します。

<dependency>
    <groupId>org.apache.solr</groupId>
    <artifactId>solr-solrj</artifactId>
    <version>6.4.2</version>
</dependency>

最新の依存関係を見つけることができます]。

3インデックスデータ

データにインデックスを付けて検索するには、 core を作成する必要があります。データにインデックスを付けるために item という名前を付けます。

その前に、検索可能になるように、サーバー上でデータを索引付けする必要があります。

  • データインポートハンドラを使用してリレーショナルデータベースから直接データをインポートしたり、Apache Tikaを使用してSolr Cellにデータをアップロードしたり、インデックスハンドラを使用してXML/XSLT、JSON、およびCSVデータをアップロードしたりできます。

3.1. 索引Solr文書

SolrInputDocument を作成することで、データを core にインデックスすることができます。まず、ドキュメントにデータを入力してから、SolrJのAPIを呼び出してドキュメントにインデックスを付ける必要があります。

SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", id);
doc.addField("description", description);
doc.addField("category", category);
doc.addField("price", price);
solrClient.add(doc);
solrClient.commit();

id は当然、異なる items に対して一意である必要があります。既に索引付けされた文書の id を持つことはその文書を更新します。

3.2. インデックスビーン

SolrJは、Java Beanを索引付けするためのAPIを提供します。 Beanにインデックスを付けるには、 @ Field アノテーションを使ってアノテーションを付ける必要があります。

public class Item {

    @Field
    private String id;

    @Field
    private String description;

    @Field
    private String category;

    @Field
    private float price;
}

Beanが完成したら、索引付けは簡単です。

solrClient.addBean(item);
solrClient.commit();

4 Solrクエリ

検索はSolrの最も強力な機能です。ドキュメントをリポジトリでインデックスに登録したら、キーワード、フレーズ、日付範囲などを検索できます。結果は関連性(スコア)によってソートされます。

4.1. 基本的なクエリ

サーバーは検索操作用のAPIを公開します。 /select または /query リクエストハンドラを呼び出すことができます。

簡単な検索をしましょう。

SolrQuery query = new SolrQuery();
query.setQuery("brand1");
query.setStart(0);
query.setRows(10);

QueryResponse response = solrClient.query(query);
List<Item> items = response.getBeans(Item.class);

SolrJは、サーバーへの要求でメインのクエリパラメータ q を内部的に使用します。 start rows が指定されていない場合、返されるレコード数は10からゼロにインデックスされます。

上記の検索クエリは、インデックスが付けられたフィールドのすべてに "brand1" という完全な単語を含むドキュメントを検索します。単純検索では大文字と小文字が区別されません。

  • 別の例を見てみましょう "rand" を含む、任意の数の文字で始まり1つの文字だけで終わる単語を検索したいです。クエリでは、ワイルドカード文字 を使用できます。

query.setQuery("** rand?");

SolrクエリはSQLのようにブール演算子もサポートします。

query.setQuery("brand1 AND (Washing OR Refrigerator)");

すべてのブール演算子はすべて大文字でなければなりません。クエリパーサーによって裏付けられたものは AND OR、NOT + 、 - です。

さらに、すべてのインデックス付きフィールドではなく特定のフィールドを検索する場合は、クエリでこれらを指定できます。

query.setQuery("description:Brand**  AND category:** Washing** ");

4.2. フレーズクエリ

ここまでは、インデックス付きフィールドでキーワードを検索していました。インデックス付きフィールドでフレーズ検索もできます。

query.setQuery("Washing Machine");

Washing Machine ”のようなフレーズがあると、Solrの標準クエリパーサーはそれを“ Washing OR Machine ”に解析します。フレーズ全体を検索するには、二重引用符で囲んで表現を追加します。

query.setQuery("\"Washing Machine\"");
  • 近接検索を使用して、特定の距離内の単語を検索できます**

2単語以上離れている単語を見つけたい場合は、次のクエリを使用できます。

query.setQuery("\"Washing equipment\"~2");

4.3. 範囲クエリ

範囲クエリを使用すると、フィールドが特定の範囲内にあるドキュメントを取得できます。

価格が100から300の範囲の商品を見つけたいとしましょう。

query.setQuery("price:[100 TO 300]");

上記のクエリでは、価格が100から300までのすべての要素が検索されます。エンドポイントを除外するために、「 } 」と「 \ { 」を使用できます。

query.setQuery("price:{100 TO 300]");

4.4. フィルタクエリ

フィルタクエリを使用して、返される可能性がある結果のスーパーセットを制限できます。フィルタクエリはスコアに影響しません。

SolrQuery query = new SolrQuery();
query.setQuery("price:[100 TO 300]");
query.addFilterQuery("description:Brand1","category:Home Appliances");

一般に、フィルタクエリは一般的に使用されるクエリを含みます。これらは再利用可能なことが多いので、検索をより効率的にするためにキャッシュされます。

5ファセット検索

ファセットは、検索結果をグループ数に整理するのに役立ちます。フィールド、クエリ、または範囲をファセットできます。

5.1. フィールドファセット

たとえば、検索結果に含まれるカテゴリの集計数を取得します。クエリに category フィールドを追加できます。

query.addFacetField("category");

QueryResponse response = solrClient.query(query);
List<Count> facetResults = response.getFacetField("category").getValues();

facetResults には、結果の各カテゴリの数が含まれます。

5.2. ファセットの照会

クエリファセットは、サブクエリのカウントを元に戻すときに非常に便利です。

query.addFacetQuery("Washing OR Refrigerator");
query.addFacetQuery("Brand2");

QueryResponse response = solrClient.query(query);
Map<String,Integer> facetQueryMap = response.getFacetQuery();

その結果、 facetQueryMap にはファセットクエリの数が含まれます。

5.3. レンジファセット

範囲ファセットは、検索結果の範囲カウントを取得するために使用されます。

次のクエリでは、100から251の間の値が25の間隔でカウントされます。

query.addNumericRangeFacet("price", 100, 275, 25);

QueryResponse response = solrClient.query(query);
List<RangeFacet> rangeFacets =  response.getFacetRanges().get(0).getCounts();

数値範囲以外に、Solrは日付範囲、間隔ファセット、およびピボットファセットもサポートします。

6. 強調表示をヒット

検索クエリのキーワードを結果で強調表示することをお勧めします。これは結果をよりよく把握するのに非常に役立ちます。いくつかの文書を索引付けし、強調表示するキーワードを定義しましょう。

itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f);
itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f);
itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f);
itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f);

SolrQuery query = new SolrQuery();
query.setQuery("Appliances");
query.setHighlight(true);
query.addHighlightField("category");
QueryResponse response = solrClient.query(query);

Map<String, Map<String, List<String>>> hitHighlightedMap = response.getHighlighting();
Map<String, List<String>> highlightedFieldMap = hitHighlightedMap.get("hm0001");
List<String> highlightedList = highlightedFieldMap.get("category");
String highLightedText = highlightedList.get(0);

highLightedText は、「Home <em>アプライアンス</em>」 として取得されます。検索キーワード Appliances <em> __でタグ付けされていることに注意してください。

Solrによって使用されるデフォルトの強調表示タグは <em> ですが、 pre および post タグを設定することでこれを変更できます。

query.setHighlightSimplePre("<strong>");
query.setHighlightSimplePost("</strong>");

7. 検索候補

Solrがサポートする重要な機能の1つは提案です。クエリのキーワードにスペルミスが含まれている場合、または検索キーワードのオートコンプリートを提案する場合は、提案機能を使用できます。

7.1. スペルチェック

標準の検索ハンドラにはスペルチェックコンポーネントは含まれていません。手動で設定する必要があります。それには3つの方法があります。設定の詳細は公式のhttps://cwiki.apache.org/confluence/display/solr/スペルチェック[wikiページ]にあります。この例では、キーワードスペルチェックにインデックス付きデータを使用する IndexBasedSpellChecker を使用します。

スペルを間違えてキーワードを検索しましょう。

query.setQuery("hme");
query.set("spellcheck", "on");
QueryResponse response = solrClient.query(query);

SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse();
Suggestion suggestion = spellCheckResponse.getSuggestions().get(0);
List<String> alternatives = suggestion.getAlternatives();
String alternative = alternatives.get(0);

私たちのインデックスは “ home”という語を含んでいるので、キーワード “ hme” の期待される代替は “ home” __であるべきです。

** 7.2. オートサジェスト用語

検索を補助するために不完全なキーワードの提案を得たいと思うかもしれません。 Solrの推奨コンポーネントは手動で設定する必要があります。設定の詳細は公式のhttps://cwiki.apache.org/confluence/display/solr/Suggester[Wikiページ]にあります。

提案を処理するために /suggest という名前のリクエストハンドラを設定しました。キーワード “ Hom” についての提案を得ましょう:

SolrQuery query = new SolrQuery();
query.setRequestHandler("/suggest");
query.set("suggest", "true");
query.set("suggest.build", "true");
query.set("suggest.dictionary", "mySuggester");
query.set("suggest.q", "Hom");
QueryResponse response = solrClient.query(query);

SuggesterResponse suggesterResponse = response.getSuggesterResponse();
Map<String,List<String>> suggestedTerms = suggesterResponse.getSuggestedTerms();
List<String> suggestions = suggestedTerms.get("mySuggester");

リスト suggestions には、すべての単語とフレーズを含める必要があります。設定に mySuggester という名前のサジェスタが設定されていることに注意してください。

8結論

この記事は、検索エンジンのSolrの機能と機能の概要です。

私たちは多くの機能に触れましたが、もちろんこれらはSolrのような高度で成熟した検索サーバーで何ができるかの表面をスクラッチしているだけです。

ここで使用されている例は、https://github.com/eugenp/tutorials/tree/master/persistence-modules/solr[GitHubでの使用]として、いつでも利用できます。