4.4. 远程查询
设置 Data Grid Sever 集群时,请使用远程查询。
要执行远程查询,缓存中的数据必须使用 Google 协议缓冲 作为无线传输和存储的编码。另外,远程查询需要 Protobuf 模式(.proto
文件)来定义数据结构和索引元素。
将 Protobuf 与远程查询搭配使用的好处是,它是语言中立的,可与 Hot Rod Java 客户端以及 REST、C++、C# 和 Node.js 客户端一起工作。
4.4.1. 远程查询示例
名为 Book
s 的对象将存储在名为"books"的数据网格缓存中。将对本书实例进行索引,因此我们为缓存启用索引:
infinispan.xml
<replicated-cache name="books"> <indexing> <indexed-entities> <indexed-entity>book_sample.Book</indexed-entity> </indexed-entities> </indexing> </replicated-cache>
或者,如果缓存没有索引,我们将 < ;encoding&
gt; 配置为 application/x-protostream
,以确保存储可以查询:
infinispan.xml
<replicated-cache name="books"> <encoding media-type="application/x-protostream"/> </replicated-cache>
每个 Book
将按照以下示例定义:我们使用 @Protofield
注释来识别消息字段以及字段上的 @ProtoDoc
注解来配置索引属性:
Book.java
import org.infinispan.protostream.annotations.ProtoDoc; import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; @ProtoDoc("@Indexed") public class Book { @ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)") @ProtoField(number = 1) final String title; @ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)") @ProtoField(number = 2) final String description; @ProtoDoc("@Field(index=Index.YES, analyze = Analyze.YES, store = Store.NO)") @ProtoField(number = 3, defaultValue = "0") final int publicationYear; @ProtoFactory Book(String title, String description, int publicationYear) { this.title = title; this.description = description; this.publicationYear = publicationYear; } // public Getter methods omitted for brevity }
在编译过程中,上例中的注释生成读取、写入和查询 Book
实例所需的工件。要启用此生成,请在新创建的带有空构造或接口的类中使用 @AutoProtoSchemaBuilder
注释:
RemoteQueryInitializer.java
import org.infinispan.protostream.SerializationContextInitializer; import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder; @AutoProtoSchemaBuilder( includeClasses = { Book.class }, schemaFileName = "book.proto", schemaFilePath = "proto/", schemaPackageName = "book_sample") public interface RemoteQueryInitializer extends SerializationContextInitializer { }
在编译后,将在配置的 schemaFilePath
中创建文件 book.proto
文件,以及注释接口的实施 RemoteQueryInitializerImpl.java
。这种 concrete 类可以直接在 Hot Rod 客户端代码中使用,以初始化序列化上下文。
将所有设置放在一起:
RemoteQuery.java
package org.infinispan; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCacheManager; import org.infinispan.client.hotrod.Search; import org.infinispan.client.hotrod.configuration.ConfigurationBuilder; import org.infinispan.query.dsl.Query; import org.infinispan.query.dsl.QueryFactory; import org.infinispan.query.remote.client.ProtobufMetadataManagerConstants; public class RemoteQuery { public static void main(String[] args) throws Exception { ConfigurationBuilder clientBuilder = new ConfigurationBuilder(); // RemoteQueryInitializerImpl is generated clientBuilder.addServer().host("127.0.0.1").port(11222) .security().authentication().username("user").password("user") .addContextInitializers(new RemoteQueryInitializerImpl()); RemoteCacheManager remoteCacheManager = new RemoteCacheManager(clientBuilder.build()); // Grab the generated protobuf schema and registers in the server. Path proto = Paths.get(RemoteQuery.class.getClassLoader() .getResource("proto/book.proto").toURI()); String protoBufCacheName = ProtobufMetadataManagerConstants.PROTOBUF_METADATA_CACHE_NAME; remoteCacheManager.getCache(protoBufCacheName).put("book.proto", Files.readString(proto)); // Obtain the 'books' remote cache RemoteCache<Object, Object> remoteCache = remoteCacheManager.getCache("books"); // Add some Books Book book1 = new Book("Infinispan in Action", "Learn Infinispan with using it", 2015); Book book2 = new Book("Cloud-Native Applications with Java and Quarkus", "Build robust and reliable cloud applications", 2019); remoteCache.put(1, book1); remoteCache.put(2, book2); // Execute a full-text query QueryFactory queryFactory = Search.getQueryFactory(remoteCache); Query<Book> query = queryFactory.create("FROM book_sample.Book WHERE title:'java'"); List<Book> list = query.execute().list(); // Voila! We have our book back from the cache! } }
4.4.2. 注册 Protobuf Schemas
要查询 protobuf 实体,您必须在 Protobuf 模式(.proto
文件)中提供有关您实体的相关元数据。
描述符存储在服务器上的专用 ___protobuf_metadata
缓存中。此缓存中的键和值都是普通字符串。因此,注册新模式就像使用 schema 名称作为键,且 schema 文件本身作为值,在这个缓存上执行 put ()
操作非常简单。
如果缓存使用授权,用户必须有 CREATE
权限才能在 ___protobuf_metadata
缓存中添加条目。如果使用默认授权设置,请至少为用户分配 deployer
角色。
或者,您可以将 schema
命令和 Data Grid CLI、Data Grid Console、REST 端点 /rest/v2/schemas
或通过 JMX 的 ProtobufMetadataManager
MBean。
即使为 Protobuf 编码条目的缓存没有字段启用索引,除非您在 Protobuf schema 文档注解 (@ProtoDoc)
中使用 @Indexed
和 @Field
来指定需要索引的哪些字段。
4.4.3. 分析
分析是将输入数据转换为您可以索引和查询的一个或多个术语的进程。虽然在 嵌入式查询 映射中是通过 Hibernate Search 注解 完成的,但支持基于 Lucene 的分析器集,在 client-server 模式下,分析器定义以平台中立的方式声明。
默认分析器
Data Grid 为远程查询提供一组默认分析程序,如下所示:
定义 | 描述 |
---|---|
| 将文本字段拆分为令牌,将空格和标点分隔为分隔符。 |
| 通过取消限制非字母的令牌化输入流,然后将所有字母转换为小写字符。空格和非字母将被丢弃。 |
| 分割空格上的文本流,并将非空格字符序列返回为令牌。 |
| 将整个文本字段视为单一令牌。 |
| 使用 Snowball Porter 过滤器窃取英语词. |
| 默认情况下,生成大小为 3 分的 ngram 令牌。 |
|
将文本字段分成比 |
这些分析器定义基于 Apache Lucene,并提供了"as-is"。有关令牌工具、过滤器和 CharFilters 的更多信息,请参阅适当的 Lucene 文档。
使用分析器定义
要使用分析器定义,请在 .proto
schema 文件中按名称引用它们。
-
包含
Analyze.YES
属性,以指示分析了属性。 -
使用
@Analyzer
注释指定分析器定义。
以下示例显示了引用的分析器定义:
/* @Indexed */ message TestEntity { /* @Field(store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "keyword")) */ optional string id = 1; /* @Field(store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = "simple")) */ optional string name = 2; }
如果使用 @ProtoField
注解的 Java 类,则声明类似如下:
@ProtoDoc("@Field(store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"keyword\"))") @ProtoField(number = 1) final String id; @ProtoDoc("@Field(store = Store.YES, analyze = Analyze.YES, analyzer = @Analyzer(definition = \"simple\"))") @ProtoField(number = 2) final String description;
创建自定义分析器定义
如果您需要自定义分析器定义,请执行以下操作:
-
创建打包在
JAR
文件中的ProgrammaticSearchMappingProvider
接口的实现。 -
在
JAR
的META-INF/services/
目录中提供名为org.infinispan.query.spi.ProgrammaticSearchMappingProvider
的文件。此文件应包含您的实施的完全限定类名称。 将
JAR
复制到 Data Grid Server 安装的lib/
目录中。重要在启动期间,您的 JAR 必须可供 Data Grid 服务器使用。您不能将其添加到已在运行的服务器。
以下是 ProgrammaticSearchMappingProvider
接口的示例实现:
import org.apache.lucene.analysis.core.LowerCaseFilterFactory; import org.apache.lucene.analysis.core.StopFilterFactory; import org.apache.lucene.analysis.standard.StandardFilterFactory; import org.apache.lucene.analysis.standard.StandardTokenizerFactory; import org.hibernate.search.cfg.SearchMapping; import org.infinispan.Cache; import org.infinispan.query.spi.ProgrammaticSearchMappingProvider; public final class MyAnalyzerProvider implements ProgrammaticSearchMappingProvider { @Override public void defineMappings(Cache cache, SearchMapping searchMapping) { searchMapping .analyzerDef("standard-with-stop", StandardTokenizerFactory.class) .filter(StandardFilterFactory.class) .filter(LowerCaseFilterFactory.class) .filter(StopFilterFactory.class); } }