ベクトルデータベース

ベクトルデータベースは、AI アプリケーションで重要なロールを果たす特殊な型のデータベースです。

ベクトルデータベースでは、クエリが従来のリレーショナルデータベースとは異なります。完全一致の代わりに、類似性検索が実行されます。クエリとしてベクトルが与えられると、ベクトルデータベースはクエリベクトルに「類似した」ベクトルを返します。この類似性が高レベルでどのように計算されるかについての詳細は、ベクトルの類似性で説明されています。

ベクトルデータベースは、データを AI モデルと統合するために使用されます。使用の最初のステップは、データをベクトルデータベースにロードすることです。次に、ユーザーのクエリが AI モデルに送信されると、最初に類似したドキュメントのセットが取得されます。これらのドキュメントはユーザーの質問のコンテキストとして機能し、ユーザーのクエリとともに AI モデルに送信されます。この手法は検索拡張生成 (RAG) として知られています。

次のセクションでは、複数のベクトルデータベース実装を使用するための Spring AI インターフェースと、いくつかの高レベルのサンプルの使用箇所について説明します。

最後のセクションは、ベクトルデータベースでの類似性検索の基礎となるアプローチをわかりやすく説明することを目的としています。

API の概要

このセクションは、Spring AI フレームワーク内の VectorStore インターフェースとその関連クラスのガイドとして機能します。

Spring AI は、VectorStore インターフェースを通じてベクトルデータベースと対話するための抽象化された API を提供します。

VectorStore インターフェース定義は次のとおりです。

public interface VectorStore {

    void add(List<Document> documents);

    Optional<Boolean> delete(List<String> idList);

    List<Document> similaritySearch(String query);

    List<Document> similaritySearch(SearchRequest request);
}

および関連する SearchRequest ビルダー:

public class SearchRequest {

	public final String query;
	private int topK = 4;
	private double similarityThreshold = SIMILARITY_THRESHOLD_ALL;
	private Filter.Expression filterExpression;

	public static SearchRequest query(String query) { return new SearchRequest(query); }

	private SearchRequest(String query) { this.query = query; }

	public SearchRequest withTopK(int topK) {...}
	public SearchRequest withSimilarityThreshold(double threshold) {...}
	public SearchRequest withSimilarityThresholdAll() {...}
	public SearchRequest withFilterExpression(Filter.Expression expression) {...}
	public SearchRequest withFilterExpression(String textExpression) {...}

	public String getQuery() {...}
	public int getTopK() {...}
	public double getSimilarityThreshold() {...}
	public Filter.Expression getFilterExpression() {...}
}

データをベクトルデータベースに挿入するには、データを Document オブジェクト内にカプセル化します。Document クラスは、PDF や Word ドキュメントなどのデータソースからのコンテンツをカプセル化し、文字列として表現されるテキストを含めます。ファイル名などの詳細を含む、キーと値のペアの形式のメタデータも含まれます。

ベクトルデータベースに挿入されると、テキストコンテンツは、埋め込みモデルを使用して数値配列、またはベクトル埋め込みと呼ばれる float[] に変換されます。Word2Vec [Wikipedia] (英語) GLoVE [Wikipedia] (英語) BERT [Wikipedia] (英語) などの埋め込みモデル、または OpenAI の text-embedding-ada-002 は、単語、文、または段落をこれらのベクトル埋め込みに変換するために使用されます。

ベクトルデータベースのロールは、これらの埋め込みの類似性検索を保存し、容易にすることです。埋め込み自体は生成しません。ベクトル埋め込みを作成するには、EmbeddingModel を利用する必要があります。

インターフェースの similaritySearch メソッドを使用すると、指定されたクエリ文字列に類似したドキュメントを取得できます。これらのメソッドは、次のパラメーターを使用して微調整できます。

  • k: 返される類似ドキュメントの最大数を指定する整数。これは、「上位 K」検索、または「K 最近傍」(KNN) と呼ばれることがよくあります。

  • threshold: 0 ~ 1 の範囲の double 値。1 に近い値ほど類似性が高いことを示します。デフォルトでは、たとえば、しきい値を 0.75 に設定すると、この値を超える類似性を持つドキュメントのみが返されます。

  • Filter.Expression: SQL の 'where' 句と同様に機能する流れるような DSL (ドメイン固有言語) 式を渡すために使用されるクラスですが、Document のメタデータのキーと値のペアにのみ適用されます。

  • filterExpression: フィルター式を文字列として受け入れる ANTLR4 に基づく外部 DSL。例: 国、年、isActive などのメタデータキーでは、次のような式を使用できます。: country == 'UK' && year >= 2020 && isActive == true.

Filter.Expression の詳細については、"メタデータフィルター" セクションを参照してください。

スキーマの初期化

一部のベクトルストアでは、使用前にバックエンドスキーマを初期化する必要があります。デフォルトでは初期化されません。適切なコンストラクター引数に boolean を渡すか、Spring Boot を使用する場合は、適切な initialize-schema プロパティを application.properties または application.yml の true に設定して、オプトインする必要があります。特定のプロパティ名については、使用しているベクトルストアのドキュメントを確認してください。

利用可能な実装

VectorStore インターフェースの利用可能な実装は次のとおりです。

将来のリリースでは、さらに多くの実装がサポートされる可能性があります。

Spring AI でサポートする必要があるベクトルデータベースがある場合は、GitHub で課題をオープンするか、実装を含めたプルリクエストを送信するとさらに良いでしょう。

VectorStore の各実装に関する情報は、この章のサブセクションに記載されています。

使用例

ベクトルデータベースの埋め込みを計算するには、使用されている高レベルの AI モデルと一致する埋め込みモデルを選択する必要があります。

例: OpenAI の ChatGPT では、OpenAiEmbeddingModel と text-embedding-ada-002 というモデルを使用します。

Spring Boot スターターの OpenAI 用の自動構成により、依存性注入のために Spring アプリケーションコンテキストで EmbeddingModel の実装が利用できるようになります。

ベクトルストアにデータをロードする一般的な使用箇所は、最初にデータを Spring AI の Document クラスにロードし、次に save メソッドを呼び出すことにより、バッチのようなジョブで実行します。

ベクトルデータベースにロードしたいデータを含む JSON ファイルを表すソースファイルへの String 参照が与えられると、Spring AI の JsonReader を使って JSON の特定のフィールドをロードし、それを小片に分割してベクトルストアの実装に渡します。VectorStore の実装は埋め込みを計算し、JSON と埋め込みをベクトルデータベースに格納します。

  @Autowired
  VectorStore vectorStore;

  void load(String sourceFile) {
            JsonReader jsonReader = new JsonReader(new FileSystemResource(sourceFile),
                    "price", "name", "shortDescription", "description", "tags");
            List<Document> documents = jsonReader.get();
            this.vectorStore.add(documents);
  }

その後、ユーザーの質問が AI モデルに渡されると、類似性検索が行われて類似のドキュメントが取得され、ユーザーの質問のコンテキストとしてプロンプトに「詰め込まれ」ます。

   String question = <question from user>
   List<Document> similarDocuments = store.similaritySearch(question);

追加のオプションを similaritySearch メソッドに渡して、取得するドキュメントの数と類似性検索のしきい値を定義できます。

メタデータフィルター

このセクションでは、クエリの結果に対して使用できるさまざまなフィルターについて説明します。

フィルターストリング

SQL のようなフィルター式を String として similaritySearch オーバーロードの 1 つに渡すことができます。

次の例を考えてみましょう。

  • "country == 'BG'"

  • "genre == 'drama' && year >= 2020"

  • "genre in ['comedy', 'documentary', 'drama']"

Filter.Expression

スムーズな API を公開する FilterExpressionBuilder を使用して Filter.Expression のインスタンスを作成できます。簡単な例は次のとおりです。

FilterExpressionBuilder b = new FilterExpressionBuilder();
Expression expression = b.eq("country", "BG").build();

次の演算子を使用して、洗練された式を作成できます。

EQUALS: '=='
MINUS : '-'
PLUS: '+'
GT: '>'
GE: '>='
LT: '<'
LE: '<='
NE: '!='

次の演算子を使用して式を組み合わせることができます。

AND: 'AND' | 'and' | '&&';
OR: 'OR' | 'or' | '||';

次の例を考えてみましょう。

Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();

次の演算子も使用できます。

IN: 'IN' | 'in';
NIN: 'NIN' | 'nin';
NOT: 'NOT' | 'not';

次の例を考えてみましょう。

Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();

ベクトルを理解する