7.8. 高度な機能

7.8.1. SearchFactory へのアクセス

SearchFactory オブジェクトは、Hibernate Search の基礎となる Lucene リソースを追跡します。これは、Lucene にネイティブにアクセスする便利な方法です。SearchFactory は FullTextSession からアクセスできます。

例: SearchFactory へのアクセス

FullTextSession fullTextSession = Search.getFullTextSession(regularSession);
SearchFactory searchFactory = fullTextSession.getSearchFactory();

7.8.2. IndexReader の使用

Lucene のクエリーは IndexReader で実行されます。Hibernate Search は、パフォーマンスを最大化するためにインデックスリーダーをキャッシュするか、更新された IndexReader 軽減 I/O 操作を取得するために他の効率的なストラテジーを提供する場合があります。コードはこれらのキャッシュされたリソースにアクセスできますが、要件がいくつかあります。

例: IndexReader のアクセス

IndexReader reader = searchFactory.getIndexReaderAccessor().open(Order.class);
try {
   //perform read-only operations on the reader
}
finally {
   searchFactory.getIndexReaderAccessor().close(reader);
}

この例では、SearchFactory は (シャード化ストラテジーに関連して) このエンティティーのクエリーに必要なインデックスを判別します。各インデックスで設定された ReaderProvider を使用して、関連するすべてのインデックスの上に複合 IndexReader を返します。この IndexReader は複数のクライアント間で共有されるため、以下のルールに従う必要があります。

  • IndexReader.close() を呼び出さず、必要に応じて readerProvider.closeReader(reader) を finally ブロックで使用します。
  • 変更操作には、この IndexReader を使用しないでください (読み取り専用の IndexReader であり、このような試行によって例外が発生します)。

これらのルール以外に、特にネイティブな Lucene クエリーを行うため、IndexReader を自由に使用できます。共有 IndexReaders を使用すると、たとえばファイルシステムから直接開くよりも、ほとんどのクエリーがより効率的になります。

open (Class…​types) メソッドの代替として、open (String…​indexNames) を使用して、1 つ以上のインデックス名で渡すことができます。このストラテジーを使用して、シャードが使用される場合に、インデックスタイプに対してインデックスのサブセットを選択することもできます。

例: インデックス名による IndexReader へのアクセス

IndexReader reader = searchFactory.getIndexReaderAccessor().open("Products.1", "Products.3");

7.8.3. Lucene ディレクトリーへのアクセス

Directory は、インデックスストレージを表すために Lucene で使用される最も一般的な抽象化です。Hibernate Search は Lucene Directory と直接対話することはありませんが、これらの対話は IndexManager 経由で抽象化されます。インデックスが必ずしもディレクトリーによって実装される必要はありません。

インデックスが Directory として表示され、アクセスする必要がある場合は、IndexManager からディレクトリーへの参照を取得できます。IndexManager を DirectoryBasedIndexManager にキャストし、getDirectoryProvider().getDirectory() を使用して基礎となる Directory への参照を取得します。これは推奨されていません.代わりに IndexReader を使用することが推奨されます。

7.8.4. シャード化インデックス

場合によっては、特定のエンティティーのインデックス付きデータを複数の Lucene インデックスに分割 (シャード) すると役に立つことがあります。

警告

シャード化は、欠点が短所を上回った場合にのみ実装する必要があります。単一の検索用にシャードをすべて開く必要があるため、シャード化されたインデックスの検索は一般的に遅くなります。

シャード化のユースケースを以下に示します。

  • 単一のインデックスが大きいと、インデックスの更新時間は遅くなります。
  • 一般的な検索は、データが顧客、地域、またはアプリケーションによってセグメント化された場合など、インデックスのサブセットのみに一致します。

デフォルトでは、シャードの数が設定されていないとシャード化は有効になりません。これには、hibernate.search.<indexName>.sharding_strategy.nbr_of_shards プロパティーを使用します。

例: インデックスのシャード化

この例では、5 つのシャードが有効にされています。

hibernate.search.<indexName>.sharding_strategy.nbr_of_shards = 5

データをサブインデックスに分割するには、IndexShardingStrategy を使用します。デフォルトのシャード化ストラテジーは、(FieldBridge によって生成された)ID 文字列表現のハッシュ値に従ってデータを分割します。これにより、シャードが大幅に分散されます。カスタムの IndexShardingStrategy を実装して、デフォルトのストラテジーを置き換えることができます。カスタムストラテジーを使用するには、hibernate.search.<indexName>.sharding_strategy プロパティーを設定する必要があります。

例: カスタムシャードストラテジーの指定

hibernate.search.<indexName>.sharding_strategy = my.shardingstrategy.Implementation

IndexShardingStrategy プロパティーでは、クエリーを実行するシャードを選択して検索を最適化することもできます。フィルターをアクティベートすることで、シャード化ストラテジーはクエリー (IndexShardingStrategy.getIndexManagersForQuery) に回答するために使用されるシャードのサブセットを選択できるため、クエリーの実行が速くなります。

各シャードには独立した IndexManager があるため、異なるディレクトリープロバイダーおよびバックエンド設定を使用するように設定できます。以下の例の Animal エンティティーの IndexManager インデックス名は Animal.0 から Animal.4 です。つまり、各シャードには所有するインデックス名の後に . (ドット) とそのインデックス番号が設定されます。

例: エンティティー解析のシャード化設定

hibernate.search.default.indexBase = /usr/lucene/indexes
hibernate.search.Animal.sharding_strategy.nbr_of_shards = 5
hibernate.search.Animal.directory_provider = filesystem
hibernate.search.Animal.0.indexName = Animal00
hibernate.search.Animal.3.indexBase = /usr/lucene/sharded
hibernate.search.Animal.3.indexName = Animal03

上記の例では、設定はデフォルトの id 文字列ハッシュストラテジーを使用し、シャードは Animal インデックスを 5 つのサブインデックスに使用しています。すべてのサブインデックスはファイルシステムのインスタンスで、各サブインデックスが保存されるディレクトリーは、以下のようになります。

  • sub-index 0: /usr/lucene/indexes/Animal00 (共有 indexBase、indexName を上書き)
  • sub-index 1: /usr/lucene/indexes/Animal.1 (共有 indexBase、デフォルトの indexName)
  • sub-index 2: /usr/lucene/indexes/Animal.2 (共有 indexBase、デフォルトの indexName)
  • sub-index 3: /usr/lucene/shared/Animal03 (上書きされた indexBase、上書きされた indexName)
  • sub-index 4: /usr/lucene/indexes/Animal.4 (共有 indexBase、デフォルトの indexName)

IndexShardingStrategy を実装する場合は、任意のフィールドを使用してシャード化の選択を判断できます。deletion、purgepurgeAll などの操作を処理するには、すべてのフィールド値またはプライマリー識別子を読み取れずにインデックスを返す必要があることもあります。このような場合、すべてのインデックスが返されるため、削除操作は、削除されるドキュメントが含まれる可能性のあるすべてのインデックスに伝播されます。

7.8.5. Lucene のスコアリングカスタマイズ

Lucene を使用するとユーザーは、org.apache.lucene.search.Similarity を拡張して、そのフラグ式をカスタマイズできます。このクラスで定義された抽象メソッドは、以下の式の係数と一致し、ドキュメント d のクエリー q のスコアを計算します。

org.apache.lucene.search.Similarity を拡張して、Lucene の診断式をカスタマイズします。抽象メソッドは、以下のようにドキュメント d のクエリー q のスコアを計算するために使用される式と一致します。

*score(q,d) = coord(q,d) · queryNorm(q) · ∑ ~t in q~ ( tf(t in d) ·
idf(t) ^2^ · t.getBoost() · norm(t,d) )*
ファクター説明

tf(t ind)

ドキュメント (d) の用語 (t) の周波数係数。

idf(t)

用語の頻度に関する記録。

coord(q,d)

指定されたドキュメントのクエリー用語がいくつあるかに基づくスコア要因。

queryNorm(q)

クエリー間でスコアを設定するために使用される正規化の要素。

t.getBoost()

フィールドブースト。

norm(t,d)

いくつかの (インデックス時間) ブーストおよび長さ要素をカプセル化します。

この式の詳細は、本書の範囲外です。詳細は、Similarity の Java ドキュメントを参照してください。

Hibernate Search では、Lucene の類似性の計算を修正する方法を利用できます。

最初に、プロパティー hibernate.search.matchity を使用して、Similarity 実装の完全に指定されたクラス名を指定すると、デフォルトの類似性を設定できます。デフォルト値は org.apache.lucene.search.DefaultSimilarity です。

また、similarity プロパティーを設定して特定のインデックスに使用される類似性を上書きすることもできます。

hibernate.search.default.similarity = my.custom.Similarity

最後に、@Similarity アノテーションを使用してクラスレベルのデフォルトの類似性を上書きできます。

@Entity
@Indexed
@Similarity(impl = DummySimilarity.class)
public class Book {
...
}

たとえば、ドキュメントに用語が表示される頻度は重要ではないと仮定します。用語が 1 回出現したドキュメントは、複数回見つかったドキュメントと同様にスコア付けされる必要があります。この場合、メソッド tf(float freq) のカスタム実装は 1.0 を返します。

警告

2 つのエンティティーが同じインデックスを共有する場合、同じ Similarity 実装を宣言する必要があります。同じクラス階層のクラスは常にインデックスを共有するため、シミュリティー実装の上書きはできません。

同様に、インデックス設定とクラスレベルの設定で類似性を定義することは、競合が発生するため意味がありません。このような設定は拒否されます。

7.8.6. 例外処理の設定

Hibernate Search では、インデックスプロセスでの例外の処理方法を設定できます。設定が指定されていない場合、デフォルトでは例外がログ出力に記録されます。以下のように例外ロギングメカニズムを明示的に宣言できます。

hibernate.search.error_handler = log

デフォルトの例外処理は、同期インデックスと非同期インデックスの両方で行われます。Hibernate Search は、デフォルトのエラー処理実装を上書きする簡単なメカニズムを提供します。

独自の実装を指定するには、handle(ErrorContext context) メソッドを提供する ErrorHandler インターフェイスを実装する必要があります。ErrorContext は、プライマリー LuceneWork インスタンス、LuceneWork、およびプライマリー例外により処理できなかった後続の LuceneWork インスタンスへの参照を提供します。

public interface ErrorContext  {
   List<LuceneWork> getFailingOperations();
   LuceneWork getOperationAtFault();
   Throwable getThrowable();
   boolean hasErrors();
}

このエラーハンドラーを Hibernate Search に登録するには、設定プロパティーで ErrorHandler 実装の完全修飾クラス名を宣言する必要があります。

hibernate.search.error_handler = CustomerErrorHandler