Java の Azure Cosmos DB for NoSQL におけるベクトルのインデックス作成とクエリ
適用対象: NoSQL
Azure Cosmos DB for NoSQL のベクトル検索は現在プレビュー機能です。 使用する前に、プレビューへの登録が必要です。 この記事では、次の手順について説明します。
- Azure Cosmos DB for NoSQL のベクトル検索のプレビューへの登録
- ベクトル検索用の Azure Cosmos DB コンテナーの設定
- ベクトル埋め込みポリシーの作成
- コンテナー インデックス作成ポリシーへのベクトル インデックスの追加
- ベクトル インデックスとベクトル埋め込みポリシーを持つコンテナーの作成
- 格納されたデータでのベクトル検索の実行。
- このガイドでは、ベクトル データを作成して、データのインデックスを作成し、コンテナー内のデータに対してクエリを実行するプロセスについて説明します。
前提条件
- 既存の Azure Cosmos DB for NoSQL アカウント。
- Azure サブスクリプションをお持ちでない場合は、Azure Cosmos DB for NoSQL を無料でお試しください。
- 既存の Azure サブスクリプションをお持ちの場合は、新しい Azure Cosmos DB for NoSQL アカウントを作成してください。
- Azure Cosmos DB Java SDK の最新バージョン。
プレビューへの登録
Azure Cosmos DB for NoSQL のベクトル検索にはプレビュー機能の登録が必要です。 次の手順で登録します。
Azure Cosmos DB for NoSQL リソース ページに移動します。
[設定] メニュー項目の [機能] ウィンドウを選択します。
[Azure Cosmos DB for NoSQL におけるベクトル検索] を選択します。
機能の説明を読み、プレビューに登録することを確認します。
プレビューに登録するには [有効にする] を選択します。
Note
登録要求は自動承認されますが、反映されるまで数分かかる場合があります。
ベクトル検索に関する手順の理解
次の手順は、Cosmos DB NoSQL アカウントをセットアップしてデータベースを作成する方法を知っていることを前提としています。 ベクトル検索機能は、現在、既存のコンテナーではサポートされていないため、新しいコンテナーを作成し、コンテナーの作成時に、コンテナー レベルのベクトル埋め込みポリシーと、ベクトル インデックス作成ポリシーを指定する必要があります。
インターネットベースの書店のデータベースを作成する例で、各書籍のタイトル、著者名、ISBN、書籍の説明を保存する場合について考えてみましょう。 また、ベクトル埋め込みを含む 2 つの特性を定義します。 1 つ目は、"contentVector" プロパティで、書籍のテキスト コンテンツから生成されたテキスト埋め込みを含みます (たとえば、埋め込みを作成する前に "title"、"author"、"isbn"、"description" プロパティを連結します)。 2 つ目は "coverImageVector" で、書籍の表紙の画像から生成されます。
- ベクトル検索を実行するフィールドのベクトル埋め込みを作成し、保存します。
- ベクトル埋め込みポリシーでベクトル埋め込みパスを指定します。
- 必要なベクトル インデックスをコンテナーのインデックス作成ポリシーに含めます。
この記事の以降のセクションでは、コンテナーに保存されている項目の以下の構造について検討します。
{
"title": "book-title",
"author": "book-author",
"isbn": "book-isbn",
"description": "book-description",
"contentVector": [2, -1, 4, 3, 5, -2, 5, -7, 3, 1],
"coverImageVector": [0.33, -0.52, 0.45, -0.67, 0.89, -0.34, 0.86, -0.78]
}
まず、CosmosContainerProperties
オブジェクトを作成します。
CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), "Partition_Key_Def");
コンテナーのベクトル埋め込みポリシーを作成します。
次に、コンテナー ベクトル ポリシーを定義する必要があります。 このポリシーは、VectorDistance システム関数でベクトル プロパティの処理方法を Azure Cosmos DB クエリ エンジンに伝えるために使われる情報を提供します。 また、ユーザーが必要な情報を選んで指定する必要がある場合に、それをベクトル インデックス作成ポリシーに通知します。 含まれるベクトル ポリシーには、次の情報が含まれます。
- "path": ベクトルを含むプロパティ パス
- "datatype": ベクトルの要素の型 (既定値 Float32)
- "dimensions": パス内の各ベクトルの長さ (既定値 1536)
- "distanceFunction": 距離/類似度の計算に使用するメトリック (既定値 Cosine)
書籍の詳細の例では、ベクトル ポリシーは次の JSON の例のようになる場合があります。
// Creating vector embedding policy
CosmosVectorEmbeddingPolicy cosmosVectorEmbeddingPolicy = new CosmosVectorEmbeddingPolicy();
CosmosVectorEmbedding embedding1 = new CosmosVectorEmbedding();
embedding1.setPath("/coverImageVector");
embedding1.setDataType(CosmosVectorDataType.FLOAT32);
embedding1.setDimensions(8L);
embedding1.setDistanceFunction(CosmosVectorDistanceFunction.COSINE);
CosmosVectorEmbedding embedding2 = new CosmosVectorEmbedding();
embedding2.setPath("/contentVector");
embedding2.setDataType(CosmosVectorDataType.FLOAT32);
embedding2.setDimensions(10L);
embedding2.setDistanceFunction(CosmosVectorDistanceFunction.DOT_PRODUCT);
cosmosVectorEmbeddingPolicy.setCosmosVectorEmbeddings(Arrays.asList(embedding1, embedding2, embedding3));
collectionDefinition.setVectorEmbeddingPolicy(cosmosVectorEmbeddingPolicy);
インデックス作成ポリシーでのベクトル インデックスの作成
ベクトル埋め込みパスを決定したら、インデックス作成ポリシーにベクトル インデックスを追加する必要があります。 現在、Azure Cosmos DB for NoSQL のベクトル検索機能は新しいコンテナーでのみサポートされているため、コンテナーの作成時にベクトル ポリシーを適用する必要があり、後で変更することはできません。 この例では、インデックス作成ポリシーは次のようになります。
IndexingPolicy indexingPolicy = new IndexingPolicy();
indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT);
ExcludedPath excludedPath1 = new ExcludedPath("/coverImageVector/*");
ExcludedPath excludedPath2 = new ExcludedPath("/contentVector/*");
indexingPolicy.setExcludedPaths(ImmutableList.of(excludedPath1, excludedPath2));
IncludedPath includedPath1 = new IncludedPath("/*");
indexingPolicy.setIncludedPaths(Collections.singletonList(includedPath1));
// Creating vector indexes
CosmosVectorIndexSpec cosmosVectorIndexSpec1 = new CosmosVectorIndexSpec();
cosmosVectorIndexSpec1.setPath("/coverImageVector");
cosmosVectorIndexSpec1.setType(CosmosVectorIndexType.QUANTIZED_FLAT.toString());
CosmosVectorIndexSpec cosmosVectorIndexSpec2 = new CosmosVectorIndexSpec();
cosmosVectorIndexSpec2.setPath("/contentVector");
cosmosVectorIndexSpec2.setType(CosmosVectorIndexType.DISK_ANN.toString());
indexingPolicy.setVectorIndexes(Arrays.asList(cosmosVectorIndexSpec1, cosmosVectorIndexSpec2, cosmosVectorIndexSpec3));
collectionDefinition.setIndexingPolicy(indexingPolicy);
最後に、コンテナー インデックス ポリシーとベクトル インデックス ポリシーを使用してコンテナーを作成します。
database.createContainer(collectionDefinition).block();
重要
挿入の最適なパフォーマンスを確保するためにインデックス作成ポリシーの "excludedPaths" セクションに追加されたベクトル パス。 ベクトル パスを "excludedPaths" に追加しないと、ベクトル挿入に対してより高い RU 料金と待機時間が発生します。
重要
現在、Azure Cosmos DB for NoSQL のベクトル検索は、新しいコンテナーでのみサポートされています。 コンテナー ベクトル ポリシーとベクトル インデックス作成ポリシーは、後では変更できないので、コンテナーの作成時に両方を設定する必要があります。 どちらのポリシーも、将来のプレビュー機能の改良で変更可能になる予定です。
ベクトル類似性検索クエリの実行
望ましいベクトル ポリシーでコンテナーを作成し、コンテナーにベクトル データを挿入すると、クエリで Vector Distance システム関数を使用してベクトル検索を行うことができます。 たとえば、料理のレシピに関する書籍を説明から検索する場合、まずクエリ テキストの埋め込みを取得する必要があります。 この例では、クエリ テキスト "food recipe "の埋め込みの生成が必要であるとします。 検索クエリの埋め込みができたら、それをベクトル検索クエリの VectorDistance 関数で使用し、次に示すようにクエリに類似するすべての項目を取得できます。
SELECT TOP 10 c.title, VectorDistance(c.contentVector, [1,2,3,4,5,6,7,8,9,10]) AS SimilarityScore
FROM c
ORDER BY VectorDistance(c.contentVector, [1,2,3,4,5,6,7,8,9,10])
このクエリは、クエリに対する類似度スコアとともに書籍のタイトルを取得します。 Java の例を次に示します。
float[] embedding = new float[10];
for (int i = 0; i < 10; i++) {
array[i] = i + 1;
}
ArrayList<SqlParameter> paramList = new ArrayList<SqlParameter>();
paramList.add(new SqlParameter("@embedding", embedding));
SqlQuerySpec querySpec = new SqlQuerySpec("SELECT c.title, VectorDistance(c.contentVector,@embedding) AS SimilarityScore FROM c ORDER BY VectorDistance(c.contentVector,@embedding)", paramList);
CosmosPagedIterable<Family> filteredFamilies = container.queryItems(querySpec, new CosmosQueryRequestOptions(), Family.class);
if (filteredFamilies.iterator().hasNext()) {
Family family = filteredFamilies.iterator().next();
logger.info(String.format("First query result: Family with (/id, partition key) = (%s,%s)",family.getId(),family.getLastName()));
}