Chapter 4. Querying embedded caches Use embedded queries when you add Data Grid as a library to custom applications. Protobuf mapping is not required with embedded queries. Indexing and querying are both done on top of Java objects. 4.1. Querying embedded caches This section explains how to query an embedded cache using an example cache named "books" that stores indexed Book instances. In this example, each Book instance defines which properties are indexed and specifies some advanced indexing options with Hibernate Search annotations as follows: Book.java package org.infinispan.sample; import java.time.LocalDate; import java.util.HashSet; import java.util.Set; import org.infinispan.api.annotations.indexing.*; // Annotate values with @Indexed to add them to indexes // Annotate each field according to how you want to index it @Indexed public class Book { @Keyword String title; @Text String description; @Keyword String isbn; @Basic LocalDate publicationDate; @Embedded Set<Author> authors = new HashSet<Author>(); } Author.java package org.infinispan.sample; import org.infinispan.api.annotations.indexing.Text; public class Author { @Text String name; @Text String surname; } Procedure Configure Data Grid to index the "books" cache and specify org.infinispan.sample.Book as the entity to index. <distributed-cache name="books"> <indexing path="USD{user.home}/index"> <indexed-entities> <indexed-entity>org.infinispan.sample.Book</indexed-entity> </indexed-entities> </indexing> </distributed-cache> Obtain the cache. 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"); Perform queries for fields in the Book instances that are stored in the Data Grid cache, as in the following example: // Get the query factory from the cache QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory(cache); // Create an Ickle query that performs a full-text search using the ':' operator on the 'title' and 'authors.name' fields // You can perform full-text search only on indexed caches Query<Book> fullTextQuery = queryFactory.create("FROM org.infinispan.sample.Book b WHERE b.title:'infinispan' AND b.authors.name:'sanne'"); // Use the '=' operator to query fields in caches that are indexed or not // Non full-text operators apply only to fields that are not analyzed Query<Book> exactMatchQuery=queryFactory.create("FROM org.infinispan.sample.Book b WHERE b.isbn = '12345678' AND b.authors.name : 'sanne'"); // You can use full-text and non-full text operators in the same query Query<Book> query=queryFactory.create("FROM org.infinispan.sample.Book b where b.authors.name : 'Stephen' and b.description : (+'dark' -'tower')"); // Get the results List<Book> found=query.execute().list(); 4.2. Entity mapping annotations Add annotations to your Java classes to map your entities to indexes. Hibernate Search API Data Grid uses the Hibernate Search API to define fine grained configuration for indexing at entity level. This configuration includes which fields are annotated, which analyzers should be used, how to map nested objects, and so on. The following sections provide information that applies to entity mapping annotations for use with Data Grid. For complete detail about these annotations, you should refer to the Hibernate Search manual . @DocumentId Unlike Hibernate Search, using @DocumentId to mark a field as identifier does not apply to Data Grid values; in Data Grid the identifier for all @Indexed objects is the key used to store the value. You can still customize how the key is indexed using a combination of @Transformable , custom types and custom FieldBridge implementations. @Transformable keys The key for each value needs to be indexed as well, and the key instance must be transformed in a String . Data Grid includes some default transformation routines to encode common primitives, but to use a custom key you must provide an implementation of org.infinispan.query.Transformer . Registering a key Transformer via annotations You can annotate your key class with org.infinispan.query.Transformable and your custom transformer implementation will be picked up automatically: @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 ... } } Registering a key Transformer via the cache indexing configuration Use the key-transformers xml element in both embedded and server config: <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> Alternatively, use the Java configuration API (embedded mode): ConfigurationBuilder builder = ... builder.indexing().enable() .addKeyTransformer(CustomKey.class, CustomTransformer.class);

Commands:
package org.infinispan.sample; import java.time.LocalDate; import java.util.HashSet; import java.util.Set; import org.infinispan.api.annotations.indexing.*; // Annotate values with @Indexed to add them to indexes // Annotate each field according to how you want to index it @Indexed public class Book { @Keyword String title; @Text String description; @Keyword String isbn; @Basic LocalDate publicationDate; @Embedded Set<Author> authors = new HashSet<Author>(); }
package org.infinispan.sample; import org.infinispan.api.annotations.indexing.Text; public class Author { @Text String name; @Text String surname; }
<distributed-cache name="books"> <indexing path="USD{user.home}/index"> <indexed-entities> <indexed-entity>org.infinispan.sample.Book</indexed-entity> </indexed-entities> </indexing> </distributed-cache>
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");
// Get the query factory from the cache QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory(cache); // Create an Ickle query that performs a full-text search using the ':' operator on the 'title' and 'authors.name' fields // You can perform full-text search only on indexed caches Query<Book> fullTextQuery = queryFactory.create("FROM org.infinispan.sample.Book b WHERE b.title:'infinispan' AND b.authors.name:'sanne'"); // Use the '=' operator to query fields in caches that are indexed or not // Non full-text operators apply only to fields that are not analyzed Query<Book> exactMatchQuery=queryFactory.create("FROM org.infinispan.sample.Book b WHERE b.isbn = '12345678' AND b.authors.name : 'sanne'"); // You can use full-text and non-full text operators in the same query Query<Book> query=queryFactory.create("FROM org.infinispan.sample.Book b where b.authors.name : 'Stephen' and b.description : (+'dark' -'tower')"); // Get the results List<Book> found=query.execute().list();
@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 } }
<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>
ConfigurationBuilder builder = builder.indexing().enable() .addKeyTransformer(CustomKey.class, CustomTransformer.class);