7.6. 手動によるインデックスの変更

Hibernate Core が変更をデータベースに適用すると、Hibernate Search はこれらの変更を検出し、インデックスを自動的に更新します (eventListener が無効でない場合)。バックアップが復元したり、データが影響を受ける場合のように、Hibernate を使用せずにデータベースに変更が加えられることがあります。このような場合、Hibernate Search は Manual Index API を公開し、インデックスから単一のエンティティーを明示的に更新または削除したり、データベース全体のインデックスを再構築したり、特定のタイプへのすべての参照を削除したりします。

これらのメソッドはすべて Lucene Index のみに影響し、変更は適用されません。

7.6.1. インデックスへのインスタンスの追加

FullTextSession.index(T エンティティー) を使用すると、特定のオブジェクトインスタンスを直接インデックスに追加または更新できます。このエンティティーがすでにインデックス化されている場合は、インデックスが更新されます。インデックスへの変更は、トランザクションコミット時にのみ適用されます。

FullTextSession.index(T エンティティー) を使用してオブジェクトまたはインスタンスを直接インデックスに追加します。このインデックスは、エンティティーがインデックス化されると更新されます。Infinispan Query は、トランザクションのコミット中に変更をインデックスに適用します。

例: FullTextSession.index(T エンティティー) を使用したエンティティーのインデックス作成

FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
Object customer = fullTextSession.load( Customer.class, 8 );
fullTextSession.index(customer);
tx.commit(); //index only updated at commit time

1 つのタイプのすべてのインスタンスを追加する場合や、すべてのインデックスタイプのインスタンスを追加する場合には、MassIndexer を使用することが推奨されます。詳細はを参照してください。

MassIndexer を使用して、タイプ (またはすべてのインデックス型) のすべてのインスタンスを追加します。詳細は、Using a MassIndexer を参照してください。

7.6.2. インデックスからのインスタンスの削除

データベースからエンティティーまたは特定タイプのすべてのエンティティーを物理的に削除しなくても、特定のタイプの単一のエンティティーまたはすべてのエンティティーを Lucene インデックスから削除できます。この操作はパージと呼ばれ、FullTextSession を介しても実行されます。

パージ操作では、データベースから物理的に削除せずに、単一つのエンティティーまたは特定タイプのすべてのエンティティーを Lucene インデックスから削除できます。この操作は FullTextSession を使用して実行されます。

例: インデックスからエンティティーの特定のインスタンスを削除

FullTextSession fullTextSession = Search.getFullTextSession(session);
Transaction tx = fullTextSession.beginTransaction();
for (Customer customer : customers) {
fullTextSession.purgeAll( Customer.class );
//optionally optimize the index
//fullTextSession.getSearchFactory().optimize( Customer.class );
tx.commit(); //index is updated at commit time

このような操作の後にインデックスを最適化することが推奨されます。

注記

メソッド index、purge、および purgeAll は FullTextEntityManager でも使用できます。

注記

すべての手動のインデックスメソッド (index、urge、および purgeAll) は、データベースではなくインデックスにのみ影響し、トランザクションであっても、トランザクションが正常にコミットされるまで適用されません。または flushToIndexes を利用します。

7.6.3. インデックスの再構築

エンティティーマッピングをインデックスに変更する場合は、インデックス全体を更新する必要があります。たとえば、別のアナライザーを使用して既存のフィールドにインデックスを付ける場合は、影響を受けるタイプのインデックスを再構築する必要があります。また、データベースが置き換えられた場合 (バックアップから復元した場合や、レガシーシステムからインポートした場合など) は、既存データからインデックスを再構築できます。Hibernate Search は以下から選択する主要なストラテジーを提供します。

インデクサーのエンティティーマッピングを変更する場合は、インデックス全体を更新する必要があります。たとえば、既存のフィールドを異なるアナライザーを使用してインデックス化する場合、インデックスは影響を受けるタイプに対して再構築する必要があります。

さらに、バックアップから復元するか、レガシーシステムからインポートすることによりデータベースが置き換えられる場合、インデックスは既存データから再構築する必要があります。Infinispan Query は、以下の主要なストラテジーを提供します。

  • FullTextSession.index() をすべてのエンティティーで使用しながら、FullTextSession.flushToIndexes() を定期的に使用。
  • MassIndexer を使用。

7.6.3.1. FlushToIndexes() の使用

このストラテジーは、既存のインデックスを削除してから、FullTextSession.purgeAll() および FullTextSession.index() を使用してすべてのエンティティーをインデックスに戻すことで設定されますが、メモリーと効率の制約があります。効率を最大限に高めるためにも、Hibernate Search はインデックス操作をバッチ処理し、コミット時に実行します。大量のデータをインデックス化する場合は、トランザクションがコミットされるまですべてのドキュメントがキューに保存されるため、メモリー消費について注意する必要があります。キューを定期的に空にしない場合は、OutOfMemoryException が発生する可能性があります。これには fullTextSession.flushToIndexes() を使用します。FullTextSession.flushToIndexes() が呼び出されるたびに (またはトランザクションがコミットされると)、バッチキューが処理され、すべてのインデックスの変更が適用されます。フラッシュ後は、変更をロールバックできないことに注意してください。

例: index() および flushToIndexes() を使用したインデックス再構築

fullTextSession.setFlushMode(FlushMode.MANUAL);
fullTextSession.setCacheMode(CacheMode.IGNORE);
transaction = fullTextSession.beginTransaction();
//Scrollable results will avoid loading too many objects in memory
ScrollableResults results = fullTextSession.createCriteria( Email.class )
    .setFetchSize(BATCH_SIZE)
    .scroll( ScrollMode.FORWARD_ONLY );
int index = 0;
while( results.next() ) {
    index++;
    fullTextSession.index( results.get(0) ); //index each element
    if (index % BATCH_SIZE == 0) {
        fullTextSession.flushToIndexes(); //apply changes to indexes
        fullTextSession.clear(); //free memory since the queue is processed
    }
}
transaction.commit();

注記

この明示的な API が優先され、より優れた制御が提供されるため、hibernate.search.default.worker.batch_size が非推奨となりました。

アプリケーションがメモリーが不足しないように、バッチサイズを使用するようにしてください.大規模なバッチサイズオブジェクトの方がデータベースより高速ですが、より多くのメモリーが必要になります。

7.6.3.2. MassIndexer の使用

Hibernate Search の MassIndexer は、複数の並列スレッドを使用してインデックスを再ビルドします。オプションで、リロードする必要のあるエンティティーを選択するか、すべてのエンティティーのインデックスを変更できます。このアプローチは、パフォーマンスを最大化するために最適化されていますが、アプリケーションをメンテナンスモードに設定する必要があります。MassIndexer がビジーな場合、インデックスのクエリーは推奨されません。

例: MassIndexer を使用したインデックスの再構築

fullTextSession.createIndexer().startAndWait();

これにより、インデックスが再構築され、インデックスが削除されてから、データベースからすべてのエンティティーが再読み込みされます。簡単に使用できますが、プロセスのスピードを上げるために調整を行うことが推奨されます。

警告

MassIndexer の進行中は、インデックスの内容未定義になります。MassIndexer が機能している間にクエリーを実行すると、一部の結果が失われる可能性が高くなります。

例: Tuned MassIndexer の使用

fullTextSession
 .createIndexer( User.class )
 .batchSizeToLoadObjects( 25 )
 .cacheMode( CacheMode.NORMAL )
 .threadsToLoadObjects( 12 )
 .idFetchSize( 150 )
 .progressMonitor( monitor ) //a MassIndexerProgressMonitor implementation
 .startAndWait();

これにより、すべての User インスタンス (およびフラグ) のインデックスが再構築され、クエリーごとに 25 個のオブジェクトのバッチを使用して User インスタンスをロードするために、12 個の並列スレッドが作成されます。また、これら 12 個のスレッドが Lucene ドキュメントを出力するには、インデックス化された埋め込み関係およびカスタム FieldBridges または ClassBridges を処理する必要もあります。スレッドは、変換プロセス中に追加属性のレイジーローディングをトリガーします。そのため、並行して機能しているスレッドは多く必要になります。実際のインデックス書き込みで稼働しているスレッドの数は、各インデックスのバックエンド設定によって定義されます。

Cachemode を CacheMode.IGNORE (デフォルト) のままにすることが推奨されます。これは、ほとんどの場合でキャッシュが不要な追加オーバーヘッドになるためです。メインのエンティティーがインデックスに含まれる列挙のようなデータに関連する場合は、パフォーマンスを向上させる可能性があるため、データに応じて他の CacheMode を有効にすると便利です。

注記

最適なパフォーマンスを実現するために理想的なスレッド数は、全体的なアーキテクチャー、データベース設計、およびデータ値によって大きく異なります。すべての内部スレッドグループには意味のある名前が付けられているため、スレッドダンプ多くのの診断ツールで簡単に識別できます。

注記

MassIndexer はトランザクションを認識しないため、開始したり、コミットしたりする必要はありません。これはトランザクション処理ではないため、ユーザーが処理中にシステムを使用するようにすることは推奨されません。これは、ユーザーが結果を見つけられず、システム負荷が高すぎる可能性があるためです。

インデックス処理にかかる時間やメモリー消費量に影響を与える他のパラメーターには、以下が含まれます。

  • hibernate.search.[default|<indexname>].exclusive_index_use
  • hibernate.search.[default|<indexname>].indexwriter.max_buffered_docs
  • hibernate.search.[default|<indexname>].indexwriter.max_merge_docs
  • hibernate.search.[default|<indexname>].indexwriter.merge_factor
  • hibernate.search.[default|<indexname>].indexwriter.merge_min_size
  • hibernate.search.[default|<indexname>].indexwriter.merge_max_size
  • hibernate.search.[default|<indexname>].indexwriter.merge_max_optimize_size
  • hibernate.search.[default|<indexname>].indexwriter.merge_calibrate_by_deletes
  • hibernate.search.[default|<indexname>].indexwriter.ram_buffer_size
  • hibernate.search.[default|<indexname>].indexwriter.term_index_interval

以前のバージョンにも max_field_length がありましたが、これは Lucene から削除されました。LimitTokenCountAnalyzer を使用すると、同様の効果を得ることができます。

すべての .indexwriter パラメーターは Lucene 固有で、Hibernate Search はこれらのパラメーターを渡します。

MassIndexer は、前方のみのスクロール可能な結果を使用して、読み込まれるプライマリーキーを繰り返し処理しますが、MySQL の JDBC ドライバーはメモリーのすべての値を読み込みます。この最適化を回避するには、idFetchSizeInteger.MIN_VALUE に設定します。