4.3. 嵌入式查询
当您将 Data Grid 作为自定义应用程序的库添加时,使用嵌入式查询。
使用嵌入式查询不需要 protobuf 映射。索引和查询都在 Java 对象之上完成。
4.3.1. 嵌入式查询示例
我们将将 Book
实例存储在名为"books"的数据网格缓存中。将对
本书实例进行索引,因此我们为缓存配置启用索引:
infinispan.xml
<distributed-cache name="books"> <indexing path="${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");
每个 Book
将按照以下示例定义;我们必须选择索引哪些属性;对于每个属性,我们可以选择使用 Hibernate Search 项目中定义的注释选择高级索引选项。
Book.java
package org.infinispan.sample; import java.time.LocalDate; import java.util.HashSet; import java.util.Set; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.*; // Annotate values with @Indexed to add them to indexes // Annotate each fields according to how you want to index it @Indexed public class Book { @FullTextField String title; @FullTextField String description; @KeywordField String isbn; @GenericField LocalDate publicationDate; @IndexedEmbedded Set<Author> authors = new HashSet<Author>(); }
Author.java
package org.infinispan.sample; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; public class Author { @FullTextField String name; @FullTextField String surname; }
假设我们在我们的 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 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.3.2. 映射实体
Data Grid 依赖于 Hibernate Search 的 API,以定义在实体级别索引的精细配置。此配置包括注解哪些字段,这些分析器应使用,如何映射嵌套对象等。Hibernate Search 手册中 提供了详细的文档。
@DocumentId
与 Hibernate Search 不同,使用 @DocumentId
将字段标记为标识符不适用于 Data Grid 值;在 Data Grid 中,所有 @Indexed
对象的标识符是用于存储值的密钥。您仍然可以使用 @Transformable
、自定义类型和自定义 FieldBridge
实施的组合来自定义键的索引方式。
@Transformable 键
每个值的密钥也需要索引,必须在 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 (embedded 模式):
ConfigurationBuilder builder = ... builder.indexing().enable() .addKeyTransformer(CustomKey.class, CustomTransformer.class);
程序映射
除了使用注解将实体映射到索引外,还可以以编程方式进行配置。
在以下示例中,我们映射了一个要存储在网格中的对象 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;