11.4. 埋め込み検索
Data Grid をライブラリーとして使用すると、埋め込み検索を利用できます。protobuf マッピングは不要であり、インデックス作成と検索の両方が Java オブジェクト上で実行されます。
11.4.1. 簡単な例
books と呼ばれる Data Grid キャッシュに Book
インスタンスを保存します。Book
インスタンスはインデックス化されるため、キャッシュのインデックスを有効にします。
Data Grid の設定:
infinispan.xml
<infinispan> <cache-container> <transport cluster="infinispan-cluster"/> <distributed-cache name="books"> <indexing> <indexed-entities> <indexed-entity>com.acme.Book</indexed-entity> </indexed-entities> </indexing> </distributed-cache> </cache-container> </infinispan>
キャッシュを取得します。
import org.infinispan.Cache; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.EmbeddedCacheManager; EmbeddedCacheManager manager = new DefaultCacheManager("infinispan.xml"); Cache<String, Book> cache = manager.getCache("books");
各 Book
は、次の例のように定義されます。インデックスを作成するプロパティーを選択する必要があります。プロパティーごとに、Hibernate Search プロジェクトで定義されたアノテーションを使用して高度なインデックスオプションを任意で選択できます。
Book.java
import org.hibernate.search.annotations.*; import java.util.Date; import java.util.HashSet; import java.util.Set; //Values you want to index need to be annotated with @Indexed, then you pick which fields and how they are to be indexed: @Indexed public class Book { @Field String title; @Field String description; @Field @DateBridge(resolution=Resolution.YEAR) Date publicationYear; @IndexedEmbedded Set<Author> authors = new HashSet<Author>(); }
Author.java
public class Author { @Field String name; @Field String surname; // hashCode() and equals() omitted }
Data Grid Cache
に複数の Book
インスタンスを保存したとすると、次の例のように、一致するフィールドを検索できます。
QueryExample.java
// get the query factory from the cache: QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory(cache); // create an Ickle query that will do a full-text search (operator ':') on fields 'title' and 'authors.name' Query<Book> fullTextQuery = queryFactory.create("FROM com.acme.Book WHERE title:'infinispan' AND authors.name:'sanne'") // The ('=') operator is not a full-text operator, thus can be used in both indexed and non-indexed caches Query<Book> exactMatchQuery = queryFactory.create("FROM com.acme.Book WHERE title = 'Programming Infinispan' AND authors.name = 'Sanne Grinnovero'") // Full-text and non-full text operators can be part of the same query Query q = queryFactory.create("FROM com.query.Book b where b.author.name = 'Stephen' and b.description : (+'dark' -'tower')"); // get the results List<Book> found=query.execute().list();
list()
とは別に、iterator()
で取得するか、ページ付けを使用するかを選択できます。
11.4.2. マッピングエンティティー
Data Grid は、エンティティーレベルでインデックス作成の詳細な設定を定義するため Hibernate Search の API に依存します。この設定には、アノテーションが付けられたフィールド、使用するアナライザー、ネストされたオブジェクトのマッピング方法などが含まれます。詳細なドキュメントは the Hibernate Search manual を参照してください。
11.4.2.1. @DocumentId
Hibernate Search とは異なり、@DocumentId
を使用してフィールドを識別子としてマーク付けすると、Data Grid は値を保存するために使用されるキーになります。すべての @Indexed
オブジェクトの識別子は、値を保存するために使用されるキーになります。@Transformable
、カスタム型、およびカスタム FieldBridge
実装の組み合わせを使用して、キーのインデックス化方法をカスタマイズできます。
11.4.2.2. @Transformable keys
各値のキーはインデックス化する必要があり、キーインスタンスを String
で変換する必要があります。Data Grid には、共通のプリミティブをエンコードするためのデフォルトの変換ルーチンが含まれていますが、カスタムキーを使用するには org.infinispan.query.Transformer
の実装を提供する必要があります。
アノテーションを使用したキートランスフォーマーの登録
キークラスに org.infinispan.query.Transformable
のアノテーションを付け、カスタムトランスフォーマー実装が自動的に選択されます。
@Transformable(transformer = CustomTransformer.class) public class CustomKey { ... } public class CustomTransformer implements Transformer { @Override public Object fromString(String s) { ... return new CustomKey(...); } @Override public String toString(Object customType) { CustomKey ck = (CustomKey) customType; return ... } }
キャッシュインデックス設定を介したキートランスフォーマーの登録
埋め込みおよびサーバー設定の両方で、key-transformers
xml 要素を使用します。
<replicated-cache name="test"> <indexing auto-config="true"> <key-transformers> <key-transformer key="com.mycompany.CustomKey" transformer="com.mycompany.CustomTransformer"/> </key-transformers> </indexing> </replicated-cache>
または、Java 設定 API(組み込みモード) を使用します。
ConfigurationBuilder builder = ... builder.indexing().enable() .addKeyTransformer(CustomKey.class, CustomTransformer.class);
11.4.2.3. プログラムによるマッピング
アノテーションを使用してエンティティーをインデックスにマップする代わりに、プログラムで設定することもできます。
次の例では、グリッドに格納され、クラスにアノテーションを付けなくても 2 つのプロパティーで検索可能にするオブジェクト Author
をマップします。
import org.apache.lucene.search.Query; import org.hibernate.search.cfg.Environment; import org.hibernate.search.cfg.SearchMapping; import org.hibernate.search.query.dsl.QueryBuilder; import org.infinispan.Cache; import org.infinispan.configuration.cache.Configuration; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.configuration.cache.Index; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.query.CacheQuery; import org.infinispan.query.Search; import org.infinispan.query.SearchManager; import java.io.IOException; import java.lang.annotation.ElementType; import java.util.Properties; SearchMapping mapping = new SearchMapping(); mapping.entity(Author.class).indexed() .property("name", ElementType.METHOD).field() .property("surname", ElementType.METHOD).field(); Properties properties = new Properties(); properties.put(Environment.MODEL_MAPPING, mapping); properties.put("hibernate.search.[other options]", "[...]"); Configuration infinispanConfiguration = new ConfigurationBuilder() .indexing().index(Index.NONE) .withProperties(properties) .build(); DefaultCacheManager cacheManager = new DefaultCacheManager(infinispanConfiguration); Cache<Long, Author> cache = cacheManager.getCache(); SearchManager sm = Search.getSearchManager(cache); Author author = new Author(1, "Manik", "Surtani"); cache.put(author.getId(), author); QueryBuilder qb = sm.buildQueryBuilderForClass(Author.class).get(); Query q = qb.keyword().onField("name").matching("Manik").createQuery(); CacheQuery cq = sm.getQuery(q, Author.class); assert cq.getResultSize() == 1;