1. 概要

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

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. データのインデックス作成

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

その前に、サーバー上でデータにインデックスを付けて、検索可能にする必要があります。

データにインデックスを付ける方法はたくさんあります。データインポートハンドラーを使用して、リレーショナルデータベースから直接データをインポートしたり、ApacheTikaを使用してSolrCellでデータをアップロードしたり、インデックスを使用してXML / XSLT、JSON、CSVデータをアップロードしたりできます。ハンドラー。

3.1. Solrドキュメントのインデックス作成

SolrInputDocument を作成することで、データをコアにインデックス付けできます。 まず、ドキュメントにデータを入力してから、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 は、当然、さまざまなアイテムに対して一意である必要があることに注意してください。 すでにインデックスが作成されているドキュメントのidがあると、そのドキュメントが更新されます。

3.2. Beanのインデックス作成

SolrJは、JavaBeanに索引を付けるための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");

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

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. フィールドファセット

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

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. レンジファセット

範囲ファセットは、検索結果の範囲カウントを取得するために使用されます。 次のクエリは、25でギャップされた100から251までの価格範囲のカウントを返します。

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「ホームアプライアンスとして取得します。 検索キーワードに注意してください電化製品でタグ付けされています Solrが使用するデフォルトの強調表示タグは 、ただし、これを変更するには、 プレ役職タグ:

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

7. 検索の提案

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

7.1. スペルチェック

標準の検索ハンドラーには、スペルチェックコンポーネントは含まれていません。 手動で構成する必要があります。 それを行うには3つの方法があります。 構成の詳細は、公式の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);

私たちのキーワードに期待される代替案 「hme」 する必要があります “家” インデックスには用語が含まれているため “家”。 ご了承くださいスペルチェック検索を実行する前にアクティブ化する必要があります。

7.2. 自動提案用語

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

提案を処理するために、/uggestという名前の要求ハンドラーを構成しました。 キーワード「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");

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

8. 結論

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

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

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