ベクトル検索
生成 AI の台頭に伴い、ベクトルデータベースはデータベースの世界で大きな注目を集めています。これらのデータベースは、高次元ベクトルの効率的な保存とクエリを可能にするため、セマンティック検索、レコメンデーションシステム、自然言語理解といったタスクに最適です。
ベクトル検索は、従来の完全一致クエリに頼るのではなく、ベクトル表現(埋め込みとも呼ばれます)を比較することで、意味的に類似したデータを検索する手法です。このアプローチにより、キーワードベースの検索を超えた、インテリジェントでコンテキストを考慮したアプリケーションが可能になります。
Spring Data の文脈において、ベクトル検索は、特に自然言語処理、レコメンデーションシステム、生成 AI といった分野において、インテリジェントでコンテキストアウェアなアプリケーション構築の新たな可能性を切り開きます。Spring Data は、使い慣れたリポジトリ抽象化を用いてベクトルベースのクエリをモデル化することで、開発者が類似性ベースのベクトル対応データベースを、Spring Data プログラミングモデルのシンプルさと一貫性とシームレスに統合することを可能にします。
MongoDB で Vector Search を使用するには、クラウドで実行されているか、Docker (英語) を使用して実行されている MongoDB Atlas インスタンスが必要です。
ベクトルモデル
型安全かつ慣用的な方法でベクトル検索をサポートするために、Spring Data は次のコア抽象化を導入しています。
Vector
Vector 型は、典型的には埋め込みモデルによって生成される n 次元の数値埋め込みを表します。Spring Data では、浮動小数点数の配列を包む軽量ラッパーとして定義され、不変性と一貫性を保証します。この型は、検索クエリの入力として、または関連するベクトル表現を格納するためのドメインエンティティのプロパティとして使用できます。
Vector vector = Vector.of(0.23f, 0.11f, 0.77f); ドメインモデルで Vector を使用すると、生の配列や数値リストを扱う必要がなくなり、より型安全で表現力豊かなメソッドでベクトルデータを処理できるようになります。この抽象化により、様々なベクトルデータベースやライブラリとの統合も容易になります。また、標準の浮動小数点表現(IEEE 754 [Wikipedia] (英語) では float と double)にマッピングされないバイナリベクトルや量子化ベクトルなど、ベンダー固有の最適化も実装できます。ドメインオブジェクトにはベクトルプロパティを持たせることができ、類似性検索に使用できます。次の例を考えてみましょう。
class Comment {
@Id String id;
String country;
String comment;
Vector embedding;
// getters, setters, …
}| ベクトルをドメインオブジェクトに関連付けると、ベクトルはエンティティライフサイクルの一部として読み込まれ、保存されるため、取得および永続化操作に追加のオーバーヘッドが発生する可能性があります。 |
検索結果
SearchResult<T> 型は、ベクトル類似度クエリの結果をカプセル化します。一致したドメインオブジェクトと、クエリベクトルとの一致度を示す関連度スコアの両方が含まれます。この抽象化により、結果のランキングを構造的に処理できるようになり、開発者はデータとそのコンテキスト関連性の両方を容易に操作できるようになります。
SearchResult<T> の使用 interface CommentRepository extends Repository<Comment, String> {
@VectorSearch(indexName = "my-index", numCandidates="#{#limit.max() * 20}")
SearchResults<Comment> searchByCountryAndEmbeddingNear(String country, Vector vector, Score score,
Limit limit);
@VectorSearch(indexName = "my-index", limit="10", numCandidates="200")
SearchResults<Comment> searchByCountryAndEmbeddingWithin(String country, Vector embedding,
Score score);
}
SearchResults<Comment> results = repository.searchByCountryAndEmbeddingNear("en", Vector.of(…), Score.of(0.9), Limit.of(10));MongoDB ベクトル検索集約 (英語) ステージでは、必須引数と制限事項が定義されています。ガイドラインに従い、 |
この例では、searchByCountryAndEmbeddingNear メソッドは SearchResult<Comment> インスタンスのリストを含む SearchResults<Comment> オブジェクトを返します。各結果には、一致した Comment エンティティとその関連性スコアが含まれます。
関連性スコアは、一致したベクトルがクエリベクトルとどの程度一致しているかを示す数値です。スコアが距離を表すか類似性を表すかによって、スコアが高いほど一致度が高くなるか低くなるかが変わります。
このスコアを計算するために使用されるスコアリング関数は、基礎となるデータベース、インデックス、入力パラメーターによって異なる場合があります。
スコア、類似度、スコアリング関数
Score 型は、検索結果の関連性を示す数値を保持します。クエリベクトルとの類似度に基づいて結果をランク付けするために使用できます。Score 型は通常、浮動小数点数であり、その解釈(高いほど良い、低いほど良い)は、使用される類似度関数によって異なります。スコアはベクトル検索の副産物であり、検索操作の成功に必須ではありません。スコア値はドメインモデルの一部ではないため、帯域外データとして表現するのが最適です。
通常、スコアは ScoringFunction によって計算されます。このスコアを計算するために使用される実際のスコアリング関数は、基盤となるデータベースによって異なり、検索インデックスまたは入力パラメーターから取得できます。
Spring Data サポートは、次のようなよく使用される関数の定数を宣言します。
- ユークリッド距離
二乗差の合計の平方根を含む n 次元空間での直線距離を計算します。
- コサイン類似度
まずドット積を計算し、その結果を長さの積で割って正規化することで、2 つのベクトル間の 山括弧 を測定します。
- 内積
要素ごとの乗算の合計を計算します。
類似度関数の選択は、検索のパフォーマンスとセマンティクスの両方に影響を与える可能性があり、多くの場合、基盤となるデータベースまたはインデックスによって決まります。Spring Data は、データベースのネイティブスコアリング関数の機能と、スコアを使用して結果を絞り込むことができるかどうかを考慮します。
MongoDB はスコアを類似度値として直接報告します。スコアリング関数はインデックス内で指定する必要があるため、ベクトル検索メソッドでは Score.scoringFunction は考慮されません。検索結果にはスコアの計算方法に関する情報がないため、スコアリング関数はデフォルトで ScoringFunction.unspecified() になります。
Score と Similarity の使用 interface CommentRepository extends Repository<Comment, String> {
@VectorSearch(…)
SearchResults<Comment> searchTop10ByEmbeddingNear(Vector vector, Score similarity);
@VectorSearch(…)
SearchResults<Comment> searchTop10ByEmbeddingNear(Vector vector, Similarity similarity);
@VectorSearch(…)
SearchResults<Comment> searchTop10ByEmbeddingNear(Vector vector, Range<Similarity> range);
}
repository.searchByEmbeddingNear(Vector.of(…), Score.of(0.9)); (1)
repository.searchByEmbeddingNear(Vector.of(…), Similarity.of(0.9)); (2)
repository.searchByEmbeddingNear(Vector.of(…), Similarity.between(0.5, 1)); (3)| 1 | 検索を実行し、類似度が 0.9 以上の結果を返します。 |
| 2 | 類似度が 0.9 以上の結果を返します。 |
| 3 | 0.5 と 1.0 以上の類似度を持つ結果を返します。 |
ベクトル探索法
ベクトル検索メソッドは、標準の Spring Data クエリメソッドと同じ規則を使用してリポジトリに定義されます。これらのメソッドは SearchResults<T> を返し、クエリベクトルを定義するために Vector パラメーターを必要とします。実際の実装は、基盤となるデータストアの内部構造と、ベクトル検索に関するその機能に依存します。
| Spring Data リポジトリを初めて使用する場合は、リポジトリ定義とクエリ方法の基本をよく理解しておいてください。 |
一般的に、検索メソッドを宣言するには、次の 2 つの方法があります。
クエリ導出
文字列ベースのクエリの宣言
ベクトル検索メソッドでは、クエリベクトルを定義するために Vector パラメーターを宣言する必要があります。
派生検索方法
派生検索メソッドは、メソッド名を使用してクエリを派生します。Vector Search は、検索メソッドを宣言する際に Vector Search を実行するために、以下のキーワードをサポートしています。
| 論理キーワード | キーワード表現 |
|---|---|
|
|
|
|
MongoDB 検索メソッドでは、@VectorSearch アノテーションを使用して、$vectorSearch (英語) 集約ステージのインデックス名を定義する必要があります。
Near および Within キーワードの使用 interface CommentRepository extends Repository<Comment, String> {
@VectorSearch(indexName = "my-index", numCandidates="200")
SearchResults<Comment> searchTop10ByEmbeddingNear(Vector vector, Score score);
@VectorSearch(indexName = "my-index", numCandidates="200")
SearchResults<Comment> searchTop10ByEmbeddingWithin(Vector vector, Range<Similarity> range);
@VectorSearch(indexName = "my-index", numCandidates="200")
SearchResults<Comment> searchTop10ByCountryAndEmbeddingWithin(String country, Vector vector, Range<Similarity> range);
}派生検索メソッドでは、ドメインモデル属性を定義して、インデックス付きフィールドの事前フィルターを作成できます。
派生検索メソッドは、メソッド名を用いてクエリの意図を表現するため、一般的に読みやすく保守性も高くなります。ただし、派生検索メソッドでは、Near/Within キーワードの 2 番目の引数として Score、Range<Score>、または ScoreFunction を宣言し、そのスコアに基づいて検索結果を絞り込む必要があります。
アノテーション付き検索方法
アノテーション付きメソッドは、クエリのセマンティクスとパラメーターを完全に制御できます。派生メソッドとは異なり、メソッド名の命名規則に依存しません。
アノテーション付き検索方法では、@VectorSearch アノテーションを使用して、$vectorSearch (英語) 集約ステージのパラメーターを定義します。
@VectorSearch 検索方法の使用 interface CommentRepository extends Repository<Comment, String> {
@VectorSearch(indexName = "cos-index", filter = "{country: ?0}", limit="100", numCandidates="2000")
SearchResults<Comment> searchAnnotatedByCountryAndEmbeddingWithin(String country, Vector embedding,
Score distance);
@VectorSearch(indexName = "my-index", filter = "{country: ?0}", limit="?3", numCandidates = "#{#limit * 20}",
searchType = VectorSearchOperation.SearchType.ANN)
List<Comment> findAnnotatedByCountryAndEmbeddingWithin(String country, Vector embedding, Score distance, int limit);
} アノテーション付き検索方法では、事前フィルターの使用のために filter を定義できます。
filter、limit、numCandidates は、検索メソッドの引数への参照を可能にする値式をサポートします。
実際のクエリをより細かく制御できるため、Spring Data はクエリとそのパラメーターに関する仮定を減らすことができます。例: Similarity 正規化では、クエリ内のネイティブスコア関数を使用して、指定された類似度をスコア述語値に正規化し、その逆も同様に行います。アノテーション付きクエリでたとえばスコアが定義されていない場合、返される SearchResult<T> のスコア値は 0 になります。
ソート
デフォルトでは、検索結果はスコア順に並べられます。Sort パラメーターを使用すると、並べ替えをオーバーライドできます。
Sort の使用 interface CommentRepository extends Repository<Comment, String> {
SearchResults<Comment> searchByEmbeddingNearOrderByCountry(Vector vector, Score score);
SearchResults<Comment> searchByEmbeddingWithin(Vector vector, Score score, Sort sort);
}カスタムソートでは、スコアをソート条件として指定することはできません。ドメインプロパティのみを参照できます。