11.5. リモート検索


リモート検索は埋め込みと非常によく似ていますが、データはネットワークとストレージの両方のエンコーディングとして Google Protocol Buffers を使用する必要があるという顕著な違いがあります。さらに、Hibernate Search アノテーションに依存せずに、データ構造とインデックス要素を定義する protobuf スキーマを記述 (または Java クラスから生成) する必要があります。

protobuf を使用すると、リモートクエリーは Java だけでなく、REST、C#、および Node.js クライアントで機能します。

11.5.1. リモートクエリーの例

組み込みクエリーから Book Sample を再確認しますが、今回は Java Hot Rod クライアントと Infinispan サーバーを使用します。Book と呼ばれるオブジェクトは books と呼ばれる Infinispan キャッシュに保存されます。Book インスタンスはインデックス化されるため、キャッシュのインデックスを有効にします。

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>

または、キャッシュのインデックス化がインデックス化されていない場合は、<encoding>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 {
}

コンパイル後、ファイル book.proto ファイルが、アノテーションが付いたインターフェイスの実装 RemoteQueryInitializerImpl.java とともに、設定された schemaFilePath に作成されます。この具体的なクラスは Hot Rod クライアントコードで直接使用して、シリアル化コンテキストを初期化します。

すべてを 1 つにまとめます。

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 エンティティーのクエリーに必要な 1 つの手順は、クライアントおよびサーバーにエンティティーに関連するメタデータ (.proto ファイル) を提供することです。

記述子は ___protobuf_metadata という名前のサーバーで専用キャッシュに保存されます。このキャッシュのキーと値はどちらもプレーンテキストの文字列です。したがって、新しいスキーマの登録は、スキーマ名をキーとして、スキーマファイル自体を値として使用して、このキャッシュに対して put() 操作を実行するのと同じくらい簡単です。

代わりに、CLI(cache-container=*:register-proto-schemas() 操作経由)、管理コンソール、REST エンドポイント /rest/v2/schemas、または JMX 経由で ProtobufMetadataManager MBean を使用できます。セキュリティーが有効になっている場合、リモートプロトコル経由でスキーマキャッシュにアクセスするには、ユーザーが '___schema_manager' ロールに属している必要があります。

注記

キャッシュに対してインデックスが有効になっている場合でも、 protobuf スキーマドキュメントアノテーション (@ProtoDoc) 内の @Indexed および @Field を使用してインデックスする必要のあるフィールドを指定しない限り、Protobuf でエンコードされたエントリーのフィールドはインデックス付けされません。

11.5.3. 分析

分析は、入力データを、インデックスを作成してクエリーできる 1 つ以上の用語に変換するプロセスです。Embedded Query のマッピングは、Lucene ベースのアナライザーのセットをサポートする Hibernate Search アノテーション を介して行われますが、クライアントサーバーモードでは、アナライザー定義はプラットフォームに依存しない方法で宣言されます。

11.5.3.1. デフォルトのアナライザー

Data Grid は、以下のようにリモートクエリーに対してデフォルトのアナライザーのセットを提供します。

定義説明

standard

テキストフィールドをトークンに分割し、空白と句読点を区切り文字として扱います。

simple

非文字で区切り、すべての文字を小文字に変換することにより、入力ストリームをトークン化します。空白と非文字は破棄されます。

whitespace

テキストストリームを空白で分割し、空白以外の文字のシーケンスをトークンとして返します。

キーワード

テキストフィールド全体を単一トークンとして扱います。

stemmer

SnowballPorter フィルターを使用して英語の単語を語幹にします。

ngram

デフォルトでサイズ 3 つのグラムである n-gram トークンを生成します。

filename

テキストフィールドを standard アナライザーよりも大きなサイズトークンに分割し、空白文字を区切り文字として扱い、すべての文字を小文字に変換します。

これらのアナライザー定義は Apache Lucene をベースとし、as-is で提供されます。tokenizers、filters、および CharFilters に関する詳細は、適切な Lucene のドキュメントを参照してください。

11.5.3.2. アナライザー定義の使用

アナライザー定義を使用するには、.proto スキーマファイルで名前でそれらを参照します。

  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 を Data Grid インストールの 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

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.