すべてのプロダクト
Search
ドキュメントセンター

Lindorm:基本機能

最終更新日:Mar 12, 2025

Lindorm ベクトルエンジンは、スカラー、ベクトル、および全文検索機能の組み合わせをサポートしています。Java High Level REST Client は、より使いやすい API をサポートしています。複雑なクエリと分析を実行する場合は、Java Low Level REST Client を使用してベクトルエンジンに接続できます。

前提条件

  • Java 開発キット(JDK)1.8 以降がインストールされている。

  • ベクトルエンジンがアクティブ化されている。ベクトルエンジンをアクティブ化する方法の詳細については、「ベクトルエンジンをアクティブ化する」をご参照ください。

  • LindormSearch がアクティブ化されている。詳細については、「LindormSearch をアクティブ化する」をご参照ください。

  • クライアントの IP アドレスが Lindorm インスタンスのホワイトリストに追加されている。詳細については、「ホワイトリストを構成する」をご参照ください。

準備

Java High Level REST Client をインストールする

たとえば、Maven プロジェクトの pom.xml ファイルに次の依存関係を追加できます。サンプルコード:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.10.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.20.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.20.0</version>
</dependency>

LindormSearch に接続する

// Elasticsearch 用の LindormSearch エンドポイントを指定します。
String search_url = "ld-t4n5668xk31ui****-proxy-search-public.lindorm.rds.aliyuncs.com";
int search_port = 30070;

String username = "user";
String password = "test";
final CredentialsProvider credentials_provider = new BasicCredentialsProvider();
credentials_provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));


RestHighLevelClient highClient = new RestHighLevelClient(
  RestClient.builder(new HttpHost( search_url, search_port, "http")).setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
      return httpClientBuilder.setDefaultCredentialsProvider(credentials_provider);
    }
  })
);

パラメーター

説明

search_url

Elasticsearch 用の LindormSearch エンドポイント。エンドポイントを取得する方法の詳細については、「Elasticsearch 用の LindormSearch エンドポイント」をご参照ください。

重要
  • アプリケーションが ECS インスタンスにデプロイされている場合は、セキュリティを強化し、ネットワークレイテンシを低減するために、VPC を使用して Lindorm インスタンスに接続することをお勧めします。

  • アプリケーションがローカルサーバーにデプロイされていて、インターネット経由で Lindorm インスタンスに接続する必要がある場合は、Lindorm コンソールでインスタンスのパブリックエンドポイントを有効にするために、次の手順を実行できます。左側のナビゲーションウィンドウで、[データベース接続] をクリックします。表示されるページで、[検索エンジン] タブをクリックします。次に、右上隅にある [パブリックエンドポイントを有効にする] をクリックします。

  • VPC を使用して Lindorm インスタンスにアクセスする場合は、search_url の値に [elasticsearch 用の Lindormsearch VPC エンドポイント] を指定します。インターネットを使用して Lindorm インスタンスにアクセスする場合は、search_url の値に [elasticsearch 用の Lindormsearch インターネットエンドポイント] を指定します。

search_port

[elasticsearch 用の Lindormsearch エンドポイント] にアクセスするために使用されるポート。このパラメーターの値は 30070 に固定されています。

username

LindormSearch に接続するために使用されるユーザー名とパスワード。

デフォルトのユーザー名とパスワードを取得するには、次の手順を実行できます。左側のナビゲーションウィンドウで、[データベース接続] をクリックします。表示されるページで、[検索エンジン] タブをクリックします。次に、このタブに表示されているユーザー名とパスワードを確認します。

password

ベクトルインデックスを作成する

説明

この例では、Map.of 構文は JDK 9 以降でのみサポートされています。JDK がこのバージョンより前の場合は、実際の JDK バージョンに基づいて構文を変更できます。

HNSW インデックス

String indexName = "vector_hnsw_test";

CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
{
  // 設定を作成する
  Map<String, Object> indexMap = new HashMap<>();
  indexMap.put("number_of_shards", 2);
  indexMap.put("knn", true);
  Map<String, Object> settings = new HashMap<>();
  settings.put("index", indexMap);
  createIndexRequest.settings(settings);
}

{
  // マッピングを作成する。
  Map<String, Object> source = new HashMap<>();
  source.put("excludes", new String[] { "vector1" });

  // "method.parameters" のマップを作成する
  Map<String, Object> parameters = new HashMap<>();
  parameters.put("m", 24);
  parameters.put("ef_construction", 500);

  // "method" のマップを作成する
  Map<String, Object> method = new HashMap<>();
  method.put("engine", "lvector");
  method.put("name", "hnsw");
  method.put("space_type", "l2");
  method.put("parameters", parameters);

  // "vector1" のマップを作成する
  Map<String, Object> vector1 = new HashMap<>();
  vector1.put("type", "knn_vector");
  vector1.put("dimension", 3);
  vector1.put("data_type", "float");
  vector1.put("method", method);

  // プロパティのマップを作成する
  Map<String, Object> properties = new HashMap<>();
  properties.put("vector1", vector1);
  properties.put("field1", Map.of("type", "long"));

  // マッピングマップを作成する
  Map<String, Object> mappings = new HashMap<>();
  mappings.put("_source", source);
  mappings.put("properties", properties);
  createIndexRequest.mapping(mappings);
}

CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
System.out.println("createIndexResponse: " + createIndexResponse);

IVFPQ インデックス

String indexName = "vector_ivfpq_test";

CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
{
  // 設定を作成する
  Map<String, Object> indexMap = new HashMap<>();
  indexMap.put("number_of_shards", 2);
  indexMap.put("knn", true);
  indexMap.put("knn.offline.construction", true);
  Map<String, Object> settings = new HashMap<>();
  settings.put("index", indexMap);
  createIndexRequest.settings(settings);
}

{
  // マッピングを作成する
  Map<String, Object> source = new HashMap<>();
  Map<String, Object> source = new HashMap<>();
  source.put("excludes", new String[] { "vector1" });
  mappings.put("_source", source);

  Map<String, Object> properties = new HashMap<>();
  int dim = 3;
  
  // vector1 プロパティ
  Map<String, Object> vector1 = new HashMap<>();
  vector1.put("type", "knn_vector");
  vector1.put("dimension", dim);
  vector1.put("data_type", "float");

  Map<String, Object> method = new HashMap<>();
  method.put("engine", "lvector");
  method.put("name", "ivfpq");
  method.put("space_type", "cosinesimil");

  Map<String, Object> parameters = new HashMap<>();
  parameters.put("m", dim);
  parameters.put("nlist", 10000);
  parameters.put("centroids_use_hnsw", true);
  parameters.put("centroids_hnsw_m", 48);
  parameters.put("centroids_hnsw_ef_construct", 500);
  parameters.put("centroids_hnsw_ef_search", 200);
  method.put("parameters", parameters);

  vector1.put("method", method);
  properties.put("vector1", vector1);

  // field1 プロパティ
  Map<String, Object> field1 = new HashMap<>();
  field1.put("type", "long");
  properties.put("field1", field1);

  mappings.put("properties", properties);
  createIndexRequest.mapping(mappings);
}

CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
System.out.println("createIndexResponse: " + createIndexResponse);

スパースベクトルインデックス

String indexName = "vector_sparse_test";

CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
{
  // 設定を作成する
  Map<String, Object> indexMap = new HashMap<>();
  indexMap.put("number_of_shards", 2);
  indexMap.put("knn", true);
  Map<String, Object> settings = new HashMap<>();
  settings.put("index", indexMap);
  createIndexRequest.settings(settings);
}

{
  // マッピングを作成する
  Map<String, Object> source = new HashMap<>();
  Map<String, Object> source = new HashMap<>();
  source.put("excludes", new String[]{"vector1"});
  mappings.put("_source", source);

  Map<String, Object> properties = new HashMap<>();

  Map<String, Object> vector1 = new HashMap<>();
  vector1.put("type", "knn_vector");
  vector1.put("data_type", "sparse_vector");

  Map<String, Object> method = new HashMap<>();
  method.put("engine", "lvector");
  method.put("name", "sparse_hnsw");
  method.put("space_type", "innerproduct");

  Map<String, Object> parameters = new HashMap<>();
  parameters.put("m", 24);
  parameters.put("ef_construction", 200);
  method.put("parameters", parameters);

  vector1.put("method", method);

  properties.put("vector1", vector1);

  Map<String, Object> field1 = new HashMap<>();
  field1.put("type", "long");
  properties.put("field1", field1);

  mappings.put("properties", properties);
  createIndexRequest.mapping(mappings);
}

CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
System.out.println("createIndexResponse: " + createIndexResponse);

データを書き込む

ベクトル列を含むインデックスにデータを書き込む方法は、通常のインデックスにデータを書き込む方法と同じです。

1 行のデータを書き込む

次のサンプルコードは、vector_test インデックスにデータを書き込む方法の例を示しています。

Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", new float[]{1.2f,1.3f,1.4f});
IndexRequest indexRequest = new IndexRequest("vector_test");
indexRequest.id("1");
indexRequest.source(fieldMap);
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);

複数の行のデータを同時に書き込む

BulkRequest bulkRequest = new BulkRequest();
{
  Map<String, Object> fieldMap = new HashMap<>();
  fieldMap.put("field1", 1);
  fieldMap.put("vector1", new float[]{2.2f,2.3f,2.4f});
  IndexRequest indexRequest = new IndexRequest("vector_test");
  indexRequest.id("1");
  indexRequest.source(fieldMap);
  bulkRequest.add(indexRequest);
}
{
  Map<String, Object> fieldMap = new HashMap<>();
  fieldMap.put("field1", 1);
  fieldMap.put("vector1", new float[]{2.2f,2.3f,2.4f});
  IndexRequest indexRequest = new IndexRequest("vector_test");
  indexRequest.id("2");
  indexRequest.source(fieldMap);
  bulkRequest.add(indexRequest);
}
{
  Map<String, Object> fieldMap = new HashMap<>();
  fieldMap.put("field1", 2);
  fieldMap.put("vector1", new float[]{1.2f,1.3f,4.4f});
  IndexRequest indexRequest = new IndexRequest("vector_test");
  indexRequest.id("3");
  indexRequest.source(fieldMap);
  bulkRequest.add(indexRequest);
}
{
  DeleteRequest deleteRequest = new DeleteRequest("vector_test", "2");
  bulkRequest.add(deleteRequest);
}
{
  Map<String, Object> fieldMap = new HashMap<>();
  fieldMap.put("field1", 3);
  fieldMap.put("vector1", new float[]{2.2f,3.3f,4.4f});
  UpdateRequest updateRequest = new UpdateRequest();
  updateRequest.index("vector_test");
  updateRequest.id("1");
  updateRequest.doc(fieldMap);
  bulkRequest.add(updateRequest);
}
BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);

スパースベクトルを書き込む

前述の方法を使用して、スパースベクトルを書き込むことができます。この場合、vector1 の形式を変更する必要があります。

Map<String, Object> vectorMap = new HashMap<>();
vectorMap.put("indices", Lists.of(10, 12, 16));
vectorMap.put("values", Lists.of(1.2, 1.3, 1.4));

Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", vectorMap);

IndexRequest indexRequest = new IndexRequest("vector_test");
indexRequest.id("1");
indexRequest.source(fieldMap);
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);

インデックスを構築する

Java High Level REST Client は、すべてのカスタムプラグイン API をサポートしているわけではありません。Low Level REST Client を使用して、_plugins API を呼び出すことができます。詳細については、「インデックスを構築する」をご参照ください。

データをクエリする

純粋なベクトルデータクエリと統合クエリで使用するために、別個のクラス LVectorExtBuilder を定義します。

package com.aliyun.lindorm;

import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.SearchExtBuilder;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;

public class LVectorExtBuilder extends SearchExtBuilder {

  final Map<String, String> searchParams;
  protected final String name;

  public LVectorExtBuilder(String name, Map<String, String> searchParams) {
    this.name = name;
    this.searchParams = searchParams;
  }

  @Override
  public void writeTo(StreamOutput out) throws IOException {
    out.writeMap(searchParams, StreamOutput::writeString, StreamOutput::writeString);
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    LVectorExtBuilder that = (LVectorExtBuilder) o;
    return Objects.equals(searchParams, that.searchParams) && Objects.equals(name, that.name);
  }

  @Override
  public int hashCode() {
    return Objects.hash(searchParams, name);
  }

  @Override
  public String getWriteableName() {
    return name;
  }

  @Override
  public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
    builder.startObject(name);
    for (Map.Entry<String, String> searchParam : searchParams.entrySet()) {
      builder.field(searchParam.getKey(), searchParam.getValue());
    }
    builder.endObject();
    return builder;
  }
}

純粋なベクトルデータをクエリする

float[] vectors = new float[]{2.2f,3.3f,4.4f};
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
  Map<String, Object> vectorMap = new HashMap<>();
  vectorMap.put("vector", vectors);
  vectorMap.put("k", topK);
  queryBody.put("knn", Map.of(vectorColumn, vectorMap));
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = Map.of("min_score", "0.8");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices(index);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);

パラメーターの説明

パラメーター構造

パラメーター

必須

説明

knn

vector

はい

クエリで使用されるベクトル。

k

はい

返される最も類似したデータレコードの数。

ext

lvector.min_score

いいえ

類似度のしきい値。返されるベクトルスコアはこの値より大きくなければなりません。返されるベクトルスコアの範囲は 0 ~ 1 です。

最小値: [0, +inf]。デフォルト値: 0

lvector.filter_type

いいえ

統合クエリのモード。有効な値:

  • pre_filter: 構造化データをフィルタリングしてから、ベクトルデータをクエリします。

  • post_filter: ベクトルデータをクエリしてから、構造化データをフィルタリングします。

このパラメーターはデフォルトでは空です。

lvector.ef_search

いいえ

インデックス構築中の動的リストの長さ。このパラメーターは、HNSW アルゴリズムにのみ適用されます。

有効な値: 1 ~ 1000。デフォルト値: 100

lvector.nprobe

いいえ

クエリするクラスターユニットの数。目的の効果を達成するために、取得率の要件に基づいてこのパラメーターの値を調整します。値が大きいほど、取得率が高く、検索パフォーマンスが低いことを示します。

最小値: 1。最大値: method.parameters.nlist パラメーターで指定された値。このパラメーターにはデフォルト値がありません。

重要

このパラメーターは、IVFPQ アルゴリズムにのみ適用されます。

lvector.reorder_factor

いいえ

元のベクトルを使用して検索結果を並べ替えます。IVFPQ アルゴリズムによって計算された距離は量子化された距離であるため、精度がいくらか失われる可能性があります。したがって、元のベクトルを使用して並べ替える必要があります。並べ替えの割合は、k * reorder_factor パラメーターで指定されます。並べ替えは、取得精度を向上させるために使用されますが、パフォーマンスオーバーヘッドが増加する可能性があります。

有効な値: 1 ~ 200。デフォルト値: 10

重要
  • このパラメーターは、IVFPQ アルゴリズムにのみ適用されます。

  • k パラメーターの値が小さい場合は、このパラメーターを 5 に設定します。k パラメーターの値が 100 より大きい場合は、このパラメーターを 1 に設定します。

指定されたフィールドを返す

クエリで指定されたフィールドを返すには、"_source": ["field1", "field2"] を指定できます。すべての非ベクトルフィールドを返すには、"_source": true を指定できます。

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
  Map<String, Object> vectorMap = new HashMap<>();
  vectorMap.put("vector", vectors);
  vectorMap.put("k", topK);
  queryBody.put("knn", Map.of(vectorColumn, vectorMap));
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = Map.of("min_score", "0.8");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
// _source を指定して、戻り値に属性を含めることができます。
searchSourceBuilder.fetchSource(new FetchSourceContext(true, new String[]{"field1", "field2"}, null));
searchRequest.source(searchSourceBuilder);
searchRequest.indices(index);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);

HSNW アルゴリズムを使用する

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
  Map<String, Object> vectorMap = new HashMap<>();
  vectorMap.put("vector", vectors);
  vectorMap.put("k", topK);
  queryBody.put("knn", Map.of(vectorColumn, vectorMap));
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = Map.of("ef_search", "100");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
// _source を指定して、戻り値に属性を含めることができます。
searchSourceBuilder.fetchSource(new FetchSourceContext(true, new String[]{"field1", "field2"}, null));
searchRequest.source(searchSourceBuilder);
searchRequest.indices(index);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);

IVFPQ アルゴリズムを使用する

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
  Map<String, Object> vectorMap = new HashMap<>();
  vectorMap.put("vector", vectors);
  vectorMap.put("k", topK);
  queryBody.put("knn", Map.of(vectorColumn, vectorMap));
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = Map.of("nprobe", "60", "reorder_factor", "5");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
// _source を指定して、戻り値に属性を含めることができます。
searchSourceBuilder.fetchSource(new FetchSourceContext(true, new String[]{"field1", "field2"}, null));
searchRequest.source(searchSourceBuilder);
searchRequest.indices(index);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);
重要
  • k パラメーターの値が 100 より大きい場合は、reorder_factor パラメーターを 1 に設定します。

  • nlist パラメーターの値が 10000 の場合は、最初に nprobe パラメーターを 60 に設定して検索効果を確認できます。取得率をさらに高める場合は、nprobe パラメーターを 80、100、120、140、160 などのより大きな値に設定できます。 nprobe パラメーターの値を増やすことによって発生するパフォーマンスオーバーヘッドは、reorder_factor パラメーターの値を調整することによって発生するパフォーマンスオーバーヘッドよりもはるかに小さくなります。ただし、nprobe パラメーターを過度に大きな値に設定しないことをお勧めします。

スパースベクトルをクエリする

前述の方法を使用して、スパースベクトルをクエリできます。この場合、vector1 の形式を変更する必要があります。

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
  Map<String, Object> knn = new HashMap<>();
  Map<String, Object> vector1 = new HashMap<>();
  vector1.put("vector", new HashMap<String, Object>() {{
    put("indices", Arrays.asList(10, 45, 16));
    put("values", Arrays.asList(0.5, 0.5, 0.2));
  }});
  vector1.put("k", 10);
  knn.put("vector1", vector1);
  queryBody.put("knn", knn);
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices(index);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);

統合クエリ

ベクトル列と共通列のクエリ条件を統合して、包括的なクエリ結果を返すことができます。実際のビジネスシナリオでは、近似クエリに post_filter モードを使用すると、より類似した検索結果が得られます。

近似クエリに pre-filter を使用する

kNN クエリ構造に filter を追加し、filter_type パラメーターを pre_filter に設定して、ベクトルデータをクエリする前に構造化データをフィルタリングできます。

説明

構造化データをフィルタリングする上限は 10,000 データレコードです。

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

// vectorColumn はベクトル列の名前です。
// field1 は属性列の名前です。
Map<String, Object> queryBody = Map.of("knn", Map.of(vectorColumn, Map.of(
  "vector", vectors,
  "k", topK,
  "filter", Map.of("range", Map.of("filed1", Map.of("gte", 0))))));
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = Map.of("filter_type", "pre_filter");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices("vector_test");
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);

近似クエリに post-filter を使用する

kNN クエリ構造に filter を追加し、filter_type パラメーターを post_filter に設定して、構造化データをフィルタリングする前にベクトルデータをクエリできます。

説明

近似クエリに post_filter モードを使用する場合は、k パラメーターをより大きな値に設定して、構造化データをフィルタリングする前により多くのベクトルデータをクエリできます。

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

// vectorColumn はベクトル列の名前です。
// field1 は属性列の名前です。
Map<String, Object> queryBody = Map.of("knn", Map.of(vectorColumn, Map.of(
  "vector", vectors,
  "k", topK,
  "filter", Map.of("range", Map.of("filed1", Map.of("gte", 0))))));
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = Map.of("filter_type", "post_filter");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices("vector_test");
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);

近似クエリに post_filter モードを使用する場合は、k パラメーターの値を増やす必要があります。IVFPQ アルゴリズムを使用する場合は、reorder_factor パラメーターの値を調整する必要があります。サンプルコード:

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

// vectorColumn はベクトル列の名前です。
// field1 は属性列の名前です。
Map<String, Object> queryBody = Map.of("knn", Map.of(vectorColumn, Map.of(
  "vector", vectors,
  "k", topK,
  "filter", Map.of("range", Map.of("filed1", Map.of("gte", 0))))));
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = Map.of("filter_type", "post_filter", "nprobe", "60", "reorder_factor", "1");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices("vector_test");
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);
重要
  • 近似クエリに post_filter モードを使用する場合は、k パラメーターの値を 10,000 ~ 20,000 の範囲内に設定できます。こうすることで、レイテンシを 100 ミリ秒未満に短縮できます。 k パラメーターの値が大きい場合は、reorder_factor パラメーターを 1 に設定します。

  • nlist パラメーターの値が 10000 の場合、最初に nprobe パラメーターを 60 に設定して検索効果を確認できます。検索効果を高めるには、nprobe パラメーターを 80、100、120、140、160 などのより大きな値に設定できます。 nprobe パラメーターの値を大きくすることによるパフォーマンスオーバーヘッドは、reorder_factor パラメーターの値を調整する場合よりもはるかに小さくなります。ただし、nprobe パラメーターを過度に大きな値に設定しないことをお勧めします。

post_filter モードを使用してフィルター条件を追加して、近似クエリを実装することもできます。

SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

// vectorColumn はベクトル列の名前です。
Map<String, Object> queryBody = Map.of("knn", Map.of(vectorColumn, Map.of(
  "vector", vectors,
  "k", topK)));
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));

// field1 >= 0
searchSourceBuilder.postFilter(QueryBuilders.rangeQuery("field1").gte(0));

searchRequest.source(searchSourceBuilder);
searchRequest.indices(index);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(searchResponse);

一般的な操作

  • すべてのインデックスとそのデータボリュームをクエリする。

    Request request = new Request("GET", "/_cat/indices?v");
    Response response = restClient.performRequest(request);
    String responseBody = EntityUtils.toString(response.getEntity());
    System.out.println(responseBody);
  • 特定のインデックスのデータボリュームをクエリする。

    CountRequest countRequest = new CountRequest(index);
    CountResponse countResponse = client.count(countRequest, RequestOptions.DEFAULT);
    System.out.println(countResponse.getCount());
  • インデックス作成情報を表示する。

    GetIndexRequest getIndexRequest = new GetIndexRequest(index);
    
    GetIndexResponse getIndexResponse = client.indices().get(getIndexRequest, RequestOptions.DEFAULT);
    
    getIndexResponse.getMappings().forEach((k, v) -> System.out.println(k + " " + v.getSourceAsMap()));
    getIndexResponse.getSettings().forEach((k, v) -> System.out.println(k + " " + v));
  • インデックス全体を削除する。

    DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
    AcknowledgedResponse deleteIndexResponse = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
    System.out.println("deleteIndexResponse: " + deleteIndexResponse.isAcknowledged());
  • クエリによってインデックスを削除する。

    DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index);
    deleteByQueryRequest.setQuery(QueryBuilders.termQuery("field1", "1"));
    BulkByScrollResponse bulkByScrollResponse = client.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
    System.out.println(bulkByScrollResponse.getTotal());