Solrによる全文検索

Solrを使用した全文検索

1. 概要

この記事では、Apache Solr検索エンジンの基本的な概念である全文検索について説明します。

The Apache Solr is an open source framework, designed to deal with millions of documents. Javaライブラリを使用した例(SolrJ)を使用して、そのコア機能について説明します。

2. Mavenの構成

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

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


    org.apache.solr
    solr-solrj
    6.4.2

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

3. インデックスデータ

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

それを行う前に、サーバー上でデータをインデックス化して、検索可能にする必要があります。

There are many different ways we can index data.データインポートハンドラーを使用して、リレーショナルデータベースから直接データをインポートしたり、ApacheTikaを使用してSolrCellでデータをアップロードしたり、インデックスハンドラーを使用して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. Beanのインデックス作成

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 items = response.getBeans(Item.class);

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

上記の検索クエリは、インデックス付きフィールドのいずれかに完全な単語“brand1”を含むドキュメントを検索します。 simple searches are not case sensitive.に注意してください

Let’s look at another example.“rand”を含む、任意の数の文字で始まり、1文字のみで終わる単語を検索します。 クエリではワイルドカード文字*?を使用できます。

query.setQuery("*rand?");

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

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

すべてのブール演算子はすべて大文字にする必要があります。クエリパーサーによってサポートされるのは、ANDOR, NOT+、および–です。

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

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

4.2. フレーズクエリ

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

query.setQuery("Washing Machine");

Washing Machine」のようなフレーズがある場合、Solrの標準クエリパーサーはそれを「Washing OR Machine」に解析します。 フレーズ全体を検索するには、二重引用符内にのみ式を追加できます。

query.setQuery("\"Washing Machine\"");

We can use proximity search to find words within specific distances。 少なくとも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.1. フィールドファセット

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

query.addFacetField("category");

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

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

5.2. クエリファセット

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

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

QueryResponse response = solrClient.query(query);
Map facetQueryMap = response.getFacetQuery();

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

5.3. 範囲ファセット

範囲ファセットを使用して、検索結果の範囲カウントを取得します。 次のクエリは、100から251までの価格帯のカウントを返します。

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

QueryResponse response = solrClient.query(query);
List 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>> hitHighlightedMap = response.getHighlighting();
Map> highlightedFieldMap = hitHighlightedMap.get("hm0001");
List highlightedList = highlightedFieldMap.get("category");
String highLightedText = highlightedList.get(0);

highLightedText“Home <em>Appliances</em>”として取得します。 検索キーワードAppliances<em>でタグ付けされていることに注意してください。 Solrで使用されるデフォルトの強調表示タグは<em>ですが、preおよびpostタグを設定することでこれを変更できます。

query.setHighlightSimplePre("");
query.setHighlightSimplePost("");

7. 検索の提案

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

7.1. スペルチェック

標準の検索ハンドラーには、スペルチェックコンポーネントは含まれていません。手動で構成する必要があります。 それには3つの方法があります。 構成の詳細は、公式のwiki pageにあります。 この例では、IndexBasedSpellCheckerを使用します。これは、キーワードのスペルチェックにインデックス付きデータを使用します。

スペルミスのあるキーワードを検索してみましょう。

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

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

インデックスには“home”.という用語が含まれているため、キーワード“hme”の代替として期待されるのは“home”です。検索を実行する前にspellcheckをアクティブ化する必要があることに注意してください。

7.2. 自動提案用語

検索を支援するために、不完全なキーワードの提案を取得したい場合があります。 Solrの提案コンポーネントは手動で構成する必要があります。 構成の詳細は、公式のwiki pageにあります。

提案を処理するために、/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> suggestedTerms = suggesterResponse.getSuggestedTerms();
List suggestions = suggestedTerms.get("mySuggester");

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

8. 結論

この記事は、Solrの検索エンジンの機能の簡単な紹介です。

多くの機能に触れましたが、これらはもちろんSolrなどの高度で成熟した検索サーバーでできることのほんの一部です。

ここで使用されている例は、いつものようにover on GitHubで利用できます。