11.5. 远程搜索


远程搜索与嵌入的显著区别非常相似,数据必须使用 Google 协议缓冲 作为无线和存储的编码。另外,需要编写(或从 Java 类生成)一个 protobuf 模式,用于定义数据结构和索引元素,而不是依赖 Hibernate 搜索注解。

使用 protobuf 允许远程查询只能用于 Java,而是用于 REST、C# 和 Node.js 客户端。

11.5.1. 远程查询示例

我们将重新访问来自嵌入式查询的 Book Sample,但这一次使用 Java Hot Rod 客户端和 Infinispan 服务器。名为 Book s 的对象将存储在名为"books"的 Infinispan 缓存中。将对本书实例进行索引,因此我们为缓存启用索引:

infinispan.xml

<infinispan>
  <cache-container default-cache="default">
    <replicated-cache name="books">
      <indexing>
        <indexed-entities>
          <indexed-entity>book_sample.Book</indexed-entity>
        </indexed-entities>
      </indexing>
    </replicated-cache>
  </cache-container>
</infinispan>

另外,如果索引缓存没有索引,我们将 &lt ;encoding& gt; 配置为 application/x-protostream,以确保存储可以查询:

infinispan.xml

<infinispan>
  <cache-container default-cache="default">
    <replicated-cache name="books">
      <encoding media-type="application/x-protostream"/>
    </replicated-cache>
  </cache-container>
</infinispan>

每个 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!
   }
}

11.5.2. Protobuf 编码条目的索引

Remote Query 示例所示,查询 protobuf 实体需要的步骤是为客户端和服务器提供有关实体(.proto 文件)的相关元数据。

描述符存储在名为 ___protobuf_metadata 的服务器中的专用缓存中。此缓存中的键和值都是普通字符串。因此,注册新模式就像使用模式的名称作为键,且 schema 文件本身用作值时对这个缓存执行 put () 操作非常简单。

或者,您可以使用 CLI (通过 cache-containerPROFILE:register-proto-schemas () 操作)、管理控制台、REST 端点 /rest/v2/schemas 或通过 JMX 的 ProtobufMetadataManager MBean。请注意,当启用安全性时,通过远程协议访问模式缓存要求用户属于 '___schema_manager' 角色。

注意

即使为 Protobuf 编码条目的缓存没有字段启用索引,除非您在 protobuf 模式文档注解 (@ProtoDoc) 中使用 @Indexed@Field 来指定需要索引的哪些字段。

11.5.3. 分析

分析是将输入数据转换为您可以索引和查询的一个或多个术语的进程。在 嵌入式 Query 映射中通过 Hibernate Search 注解 完成,但支持基于 Lucene 的分析器集,在 client-server 模式中,分析器定义以平台中立的方式声明。

11.5.3.1. 默认分析器

Data Grid 为远程查询提供一组默认分析程序,如下所示:

定义描述

standard

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

simple

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

空格

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

关键字

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

stemmer

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

ngram

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

filename

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

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

11.5.3.2. 使用分析器定义

要使用分析器定义,请在 .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;

11.5.3.3. 创建自定义分析器定义

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

  1. 创建打包在 JAR 文件中的 ProgrammaticSearchMappingProvider 接口的实现。
  2. JARMETA-INF/services/ 目录中提供名为 org.infinispan.query.spi.ProgrammaticSearchMappingProvider 的文件。此文件应包含您的实施的完全限定类名称。
  3. JAR 复制到数据网格安装的 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.