第17章 Infinispan クエリーの使用

17.1. はじめに

Red Hat JBoss Data Grid のライブラリーモードで Querying API を使用すると、キーではなく値のプロパティーを使用してグリッドでエントリーを検索できます。以下のような機能が提供されます。

  • キーワード、範囲、ファジー、ワイルドカード、およびフレーズのクエリー
  • クエリーの組み合わせ
  • クエリー結果のソート、フィルター、およびページ編集

Apache Lucene および Hibernate Search をベースとしたこの API は Red Hat JBoss Data Grid でサポートされます。さらに、Red Hat JBoss Data Grid はインデックスを使用しない検索とインデックスを使用する検索の両方を許可する代替のメカニズムを提供します。詳細は「Infinispan Query DSL」を参照してください。

クエリーの有効化

リモートクライアントサーバーモードでは、Querying API はデフォルトで有効になっています。ライブラリーモードで有効にする方法は Red Hat JBoss Data Grid の『Administration and Configuration Guide』を参照してください。

17.2. Red Hat JBoss Data Grid のクエリーのインストール

Red Hat JBoss Data Grid では、クエリーの実行に必要な JAR ファイルは Red Hat JBoss Data Grid のライブラリーモードおよびリモートクライアントサーバーモードのダウンロード内にパッケージ化されています。

Red Hat JBoss Data Grid の ダウンロードおよびインストールに関する詳細は、 『Getting Started Guide』の「Download and Install JBoss Data Grid」の章を参照してください。

さらに、以下の Maven 依存関係を定義する必要があります。

<dependency>
 <groupId>org.infinispan</groupId>
 <artifactId>infinispan-embedded-query</artifactId>
 <version>${version.infinispan}</version>
</dependency>
警告

Infinispan Query API は Hibernate Search と Lucene API を直接公開し、infinispan-embedded-query.jar ファイル内に埋め込むことはできません。他のバージョンの Hibernate Search と Lucene が infinispan-embedded-query と同じデプロイメントに含まれないようにしてください。これらが含まれると、クラスパスの競合が発生する原因となり、予期せぬ動作が実行されます。

17.3. Red Hat JBoss Data Grid でのクエリー

17.3.1. Hibernate Search およびクエリーモジュール

Red Hat JBoss Data Grid では、ユーザーは特定の項目を保存されたデータセット全体でクエリーできます。アプリケーションは常に特定のキーを認識できるわけではありませんが、クエリーモジュールを使用すると値の異なる部分をクエリーできます。

プロパティーの一部を基にしてオブジェクトを検索することができます。例を以下に示します。

  • 赤い車をすべて読み出し (メタデータの完全一致)。
  • 特定トピックに関するすべての本を検索 (完全テキスト検索および関連度スコア)

データの完全一致は、MapReduce 関数で実装することもできますが、完全テキストおよび関連度ベースのスコアはクエリーモジュールを介してのみ実行できます。

警告

現在、クエリー機能はリッチドメインオブジェクトを対象にしており、プリミティブ値は現在クエリーではサポートされていません。'

17.3.2. Apache Lucene およびクエリーモジュール

分散されたグリッドに保存されたデータセット全体でクエリーを実行するため、Red Hat JBoss Data Grid は Apache Lucene のインデックス化ツールと Hibernate Search の機能を利用します。

  • Apache Lucene はドキュメントインデックス化ツールおよび検索エンジンです。JBoss Data Grid は Apache Lucene 5.5.1 を使用します。
  • JBoss Data Grid のクエリーモジュールは、Hibernate Search をベースとしたツールキットです。Java オブジェクトを、Apache Lucene によってインデックス化およびクエリー可能なドキュメントと似た形式に縮小します。

JBoss Data Grid では、クエリーモジュールは Hibernate Search のインデックス化アノテーションが付けられた値をインデックス化し、Apache Lucene を基にインデックスを更新します。

Hibernate Search は、データに保存されたエントリーの変更を阻止し、対応するインデックス化操作を生成します。

17.4. インデックス化

17.4.1. インデックス化

インデックス化が設定されると、クエリーモジュールは追加、更新、または削除されたキャッシュエントリーを透過的にインデックス化します。インデックスはクエリーのパフォーマンスを向上しますが、更新中は追加のオーバーヘッドが発生します。インデックスを使用しないクエリーに関する詳細は、「Infinispan Query DSL」を参照してください。

グリッドにすでに存在するデータに対しては、最初の Lucene インデックスを作成します。関連するプロパティーとアノテーションが追加された後、「インデックスの再構築」に示された最初のバッチインデックスをトリガーします。

17.4.2. トランザクションおよび非トランザクションキャッシュによるインデックス化

Red Hat JBoss Data Grid では、トランザクションとインデックス化の関係は次のようになります。

  • トランザクションキャッシュである場合、コミット処理の後にリスナーを使用して (コミット後のリスナー) インデックスの更新が適用されます。インデックスの更新に失敗しても書き込みに失敗しません。
  • 非トランザクションキャッシュである場合、イベント完了後に動作するリスナー (イベント後のリスナー) を使用してインデックスの更新が適用されます。インデックスの更新に失敗しても書き込みに失敗しません。

17.4.3. プログラムを使用したインデックス化設定

インデックス化は、XML 設定ファイルを使用せずにプログラムを使用して設定できます。

この例では、Red Hat JBoss Data Grid はプログラムによって起動されます。また、グリッドに格納され、クラスにアノテーションを付けずに 2 つのプロパティーを使用して検索可能な Author オブジェクトもマップします。

プログラムを使用したインデックス化設定

SearchMapping mapping = new SearchMapping();
mapping.entity(Author.class).indexed().providedId()
        .property("name", ElementType.METHOD).field()
        .property("surname", ElementType.METHOD).field();

Properties properties = new Properties();
properties.put(org.hibernate.search.cfg.Environment.MODEL_MAPPING, mapping);
properties.put("[other.options]", "[...]");

Configuration infinispanConfiguration = new ConfigurationBuilder()
        .indexing()
        .index(Index.LOCAL)
        .withProperties(properties)
        .build();

DefaultCacheManager cacheManager = new DefaultCacheManager(infinispanConfiguration);

Cache<Long, Author> cache = cacheManager.getCache();
SearchManager sm = Search.getSearchManager(cache);

Author author = new Author(1, "FirstName", "Surname");
cache.put(author.getId(), author);

QueryBuilder qb = sm.buildQueryBuilderForClass(Author.class).get();
Query q = qb.keyword().onField("name").matching("FirstName").createQuery();
CacheQuery cq = sm.getQuery(q, Author.class);
Assert.assertEquals(cq.getResultSize(), 1);

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

Lucene インデックスは、キャッシュ内のデータストアから再構築することによって、必要な場合に再構築できます。

インデックスは以下の場合に再構築する必要があります。

  • タイプでインデックス化されている内容の定義が変更されている。
  • Analyser などのインデックスの定義方法に影響を与えるパラメーターが変更されている。
  • インデックスがシステム管理者のエラーにより、破壊または破損している。

インデックスを再構築するには、以下のように MassIndexer への参照を取得し、開始します。

SearchManager searchManager = Search.getSearchManager(cache);
searchManager.getMassIndexer().start();

この操作はグリッド内のすべてのデータを再処理するため、時間がかかる場合があります。

17.5. 検索

検索を実行するには、Lucene クエリーを作成します (「Lucene ベースのクエリー API を使用した Lucene クエリーの構築」を参照)。クエリーを org.infinispan.query.CacheQuery でラップして Lucene ベースの API から必要な機能を取得します。以下のコードはインデックス化されたフィールドに対してクエリーを準備します。このコードを実行すると、Book のリストが返されます。

Infinispan クエリーを使用した検索の作成および実行

QueryBuilder qb = Search.getSearchManager(cache).buildQueryBuilderForClass(Book.class).get();

org.apache.lucene.search.Query query = qb
    .keyword()
    .onFields("title", "author")
    .matching("Java rocks!")
    .createQuery();

// wrap Lucene query in a org.infinispan.query.CacheQuery
CacheQuery cacheQuery = Search.getSearchManager(cache).getQuery(query);

List list = cacheQuery.list();