Elasticsearch

このセクションでは、ドキュメントの埋め込みを保存し、類似性検索を実行するための Elasticsearch VectorStore のセットアップについて説明します。

Elasticsearch (英語) は、Apache Lucene ライブラリをベースにしたオープンソースの検索および分析エンジンです。

前提条件

実行中の Elasticsearch インスタンス。次のオプションが利用可能です。

自動構成

Spring AI は、Elasticsearch ベクトルストア用の Spring Boot 自動構成を提供します。これを有効にするには、プロジェクトの Maven pom.xml または Gradle build.gradle ビルドファイルに次の依存関係を追加します。

  • Maven

  • Gradle

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-elasticsearch-store-spring-boot-starter</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-elasticsearch-store-spring-boot-starter'
}

3.3.0 より前の spring-boot バージョンの場合、バージョン> 8.13.3 で elasticsearch-java 依存関係を明示的に追加する必要があります。そうしないと、使用される古いバージョンは実行されるクエリと互換性がなくなります。

  • Maven

  • Gradle

<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.13.3</version>
</dependency>
dependencies {
    implementation 'co.elastic.clients:elasticsearch-java:8.13.3'
}
Spring AI BOM をビルドファイルに追加するには、"依存関係管理" セクションを参照してください。
リポジトリセクションを参照して、ビルドファイルに Maven Central リポジトリやスナップショットリポジトリを追加します。

ベクトルストアの実装では必要なスキーマを初期化できますが、適切なコンストラクターで initializeSchema ブール値を指定するか、application.properties ファイルで …​initialize-schema=true を設定することで、オプトインする必要があります。または、初期化をオプトアウトし、Elasticsearch クライアントを使用して手動でインデックスを作成することもできます。これは、インデックスに高度なマッピングや追加の構成が必要な場合に役立ちます。

これは重大な変更です。Spring AI の以前のバージョンでは、このスキーマの初期化はデフォルトで行われていました。

デフォルト値と構成オプションについては、ベクトルストアの構成パラメーターのリストを参照してください。これらのプロパティは、ElasticsearchVectorStoreOptions Bean を構成することによっても設定できます。

さらに、設定済みの EmbeddingModel Bean が必要です。詳細については、"EmbeddingModel" セクションを参照してください。

これで、ElasticsearchVectorStore をアプリケーション内のベクトルストアとして自動接続できるようになりました。

@Autowired VectorStore vectorStore;

// ...

List <Document> documents = List.of(
    new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
    new Document("The World is Big and Salvation Lurks Around the Corner"),
    new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));

// Add the documents to Elasticsearch
vectorStore.add(documents);

// Retrieve documents similar to a query
List<Document> results = this.vectorStore.similaritySearch(SearchRequest.builder().query("Spring").topK(5).build());

プロパティの構成

Elasticsearch に接続して ElasticsearchVectorStore を使用するには、インスタンスのアクセス詳細を提供する必要があります。簡単な構成は、Spring Boot の application.yml を介して提供できます。

spring:
  elasticsearch:
    uris: <elasticsearch instance URIs>
    username: <elasticsearch username>
    password: <elasticsearch password>
  ai:
    vectorstore:
      elasticsearch:
        initialize-schema: true
        index-name: custom-index
        dimensions: 1536
        similarity: cosine
        batching-strategy: TOKEN_COUNT # Optional: Controls how documents are batched for embedding

spring.elasticsearch.* で始まる Spring Boot プロパティは、Elasticsearch クライアントを構成するために使用されます。

プロパティ 説明 デフォルト値

spring.elasticsearch.connection-timeout

Elasticsearch との通信時に使用される接続タイムアウト。

1s

spring.elasticsearch.password

Elasticsearch での認証用のパスワード。

-

spring.elasticsearch.username

Elasticsearch での認証用のユーザー名。

-

spring.elasticsearch.uris

使用する Elasticsearch インスタンスのカンマ区切りリスト。

localhost:9200

spring.elasticsearch.path-prefix

Elasticsearch に送信されるすべてのリクエストのパスに追加されるプレフィックス。

-

spring.elasticsearch.restclient.sniffer.delay-after-failure

失敗後にスケジュールされたスニフ実行の遅延。

1m

spring.elasticsearch.restclient.sniffer.interval

連続する通常のスニフ実行間の間隔。

5m

spring.elasticsearch.restclient.ssl.bundle

SSL バンドル名。

-

spring.elasticsearch.socket-keep-alive

クライアントと Elasticsearch 間のソケットキープアライブを有効にするかどうか。

false

spring.elasticsearch.socket-timeout

Elasticsearch との通信時に使用されるソケットタイムアウト。

30s

spring.ai.vectorstore.elasticsearch.* で始まるプロパティは、ElasticsearchVectorStore を構成するために使用されます。

プロパティ 説明 デフォルト値

spring.ai.vectorstore.elasticsearch.initialize-schema

必要なスキーマを初期化するかどうか

false

spring.ai.vectorstore.elasticsearch.index-name

ベクトルを格納するインデックスの名前

spring-ai-document-index

spring.ai.vectorstore.elasticsearch.dimensions

ベクトルの次元数

1536

spring.ai.vectorstore.elasticsearch.similarity

使用する類似度関数

cosine

spring.ai.vectorstore.elasticsearch.batching-strategy

埋め込みを計算するときにドキュメントをバッチ処理する戦略。オプションは TOKEN_COUNT または FIXED_SIZE です

TOKEN_COUNT

次の類似度関数が利用可能です。

  • cosine - デフォルト。ほとんどのユースケースに適しています。ベクトル間のコサイン類似度を測定します。

  • l2_norm - ベクトル間のユークリッド距離。値が低いほど類似性が高くなります。

  • dot_product - 正規化されたベクトル(例: OpenAI 埋め込み)に最適なパフォーマンス。

それぞれの詳細については、密なベクトルに関する Elasticsearch ドキュメント (英語) を参照してください。

メタデータフィルタリング

Elasticsearch でも、汎用的でポータブルなメタデータフィルターを活用できます。

例: 次のいずれかのテキスト式言語を使用できます。

vectorStore.similaritySearch(SearchRequest.builder()
        .query("The World")
        .topK(TOP_K)
        .similarityThreshold(SIMILARITY_THRESHOLD)
        .filterExpression("author in ['john', 'jill'] && 'article_type' == 'blog'").build());

または、Filter.Expression DSL を使用してプログラム的に次のようにします。

FilterExpressionBuilder b = new FilterExpressionBuilder();

vectorStore.similaritySearch(SearchRequest.builder()
        .query("The World")
        .topK(TOP_K)
        .similarityThreshold(SIMILARITY_THRESHOLD)
        .filterExpression(b.and(
                b.in("author", "john", "jill"),
                b.eq("article_type", "blog")).build()).build());
これらの (ポータブル) フィルター式は、独自の Elasticsearch クエリ文字列クエリ (英語) に自動的に変換されます。

例: この移植可能なフィルター式:

author in ['john', 'jill'] && 'article_type' == 'blog'

独自の Elasticsearch フィルター形式に変換されます。

(metadata.author:john OR jill) AND metadata.article_type:blog

手動構成

Spring Boot の自動構成を使用する代わりに、Elasticsearch ベクトルストアを手動で構成できます。そのためには、プロジェクトに spring-ai-elasticsearch-store を追加する必要があります。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-elasticsearch-store</artifactId>
</dependency>

または、Gradle build.gradle ビルドファイルに保存します。

dependencies {
    implementation 'org.springframework.ai:spring-ai-elasticsearch-store'
}

Elasticsearch、RestClient、Bean を作成します。カスタム RestClient の構成に関する詳細については、Elasticsearch ドキュメント (英語) を参照してください。

@Bean
public RestClient restClient() {
    return RestClient.builder(new HttpHost("<host>", 9200, "http"))
        .setDefaultHeaders(new Header[]{
            new BasicHeader("Authorization", "Basic <encoded username and password>")
        })
        .build();
}

次に、ビルダーパターンを使用して ElasticsearchVectorStore Bean を作成します。

@Bean
public VectorStore vectorStore(RestClient restClient, EmbeddingModel embeddingModel) {
    ElasticsearchVectorStoreOptions options = new ElasticsearchVectorStoreOptions();
    options.setIndexName("custom-index");    // Optional: defaults to "spring-ai-document-index"
    options.setSimilarity(COSINE);           // Optional: defaults to COSINE
    options.setDimensions(1536);             // Optional: defaults to model dimensions or 1536

    return ElasticsearchVectorStore.builder(restClient, embeddingModel)
        .options(options)                     // Optional: use custom options
        .initializeSchema(true)               // Optional: defaults to false
        .batchingStrategy(new TokenCountBatchingStrategy()) // Optional: defaults to TokenCountBatchingStrategy
        .build();
}

// This can be any EmbeddingModel implementation
@Bean
public EmbeddingModel embeddingModel() {
    return new OpenAiEmbeddingModel(new OpenAiApi(System.getenv("OPENAI_API_KEY")));
}

ネイティブクライアントへのアクセス

Elasticsearch ベクトルストアの実装は、getNativeClient() メソッドを通じて、基盤となるネイティブ Elasticsearch クライアント (ElasticsearchClient) へのアクセスを提供します。

ElasticsearchVectorStore vectorStore = context.getBean(ElasticsearchVectorStore.class);
Optional<ElasticsearchClient> nativeClient = vectorStore.getNativeClient();

if (nativeClient.isPresent()) {
    ElasticsearchClient client = nativeClient.get();
    // Use the native client for Elasticsearch-specific operations
}

ネイティブクライアントを使用すると、VectorStore インターフェースでは公開されない可能性がある Elasticsearch 固有の機能や操作にアクセスできます。