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>

或者,如果缓存没有索引,我们将 &lt ;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 为远程查询提供一组默认分析程序,如下所示:

定义描述

standard

将文本字段拆分为令牌,将空格和标点分隔为分隔符。

simple

通过取消限制非字母的令牌化输入流,然后将所有字母转换为小写字符。空格和非字母将被丢弃。

空格

分割空格上的文本流,并将非空格字符序列返回为令牌。

关键字

将整个文本字段视为单一令牌。

stemmer

使用 Snowball Porter 过滤器窃取英语词.

ngram

默认情况下,生成大小为 3 分的 ngram 令牌。

filename

将文本字段分成比 标准 分析器更大的令牌,将空格视为分隔符,并将所有字母转换为小写字符。

这些分析器定义基于 Apache Lucene,并提供了"as-is"。有关令牌工具、过滤器和 CharFilters 的更多信息,请参阅适当的 Lucene 文档。

使用分析器定义

要使用分析器定义,请在 .proto schema 文件中按名称引用它们。

  1. 包含 Analyze.YES 属性,以指示分析了属性。
  2. 使用 @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;
创建自定义分析器定义

如果您需要自定义分析器定义,请执行以下操作:

  1. 创建打包在 JAR 文件中的 ProgrammaticSearchMappingProvider 接口的实现。
  2. JARMETA-INF/services/ 目录中提供名为 org.infinispan.query.spi.ProgrammaticSearchMappingProvider 的文件。此文件应包含您的实施的完全限定类名称。
  3. 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);
   }
}
Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.