次の方法で共有


Java の Azure Cosmos DB for NoSQL におけるベクトルのインデックス作成とクエリ

この記事では、ベクター データの作成、データのインデックス作成、コンテナー内のデータのクエリの実行を行う方法について説明します。

ベクター インデックス作成と検索を使用する前に、まず Azure Cosmos DB for NoSQL でベクター検索を有効にする必要があります。 ベクター検索用に Azure Cosmos DB コンテナーを設定したら、ベクター埋め込みポリシーを作成します。 次に、コンテナー インデックス作成ポリシーにベクター インデックスを追加します。 次に、ベクター インデックスとベクター埋め込みポリシーを含むコンテナーを作成します。 最後に、格納されたデータに対してベクター検索を実行します。

前提条件

機能を有効にする

Azure Cosmos DB for NoSQL のベクター検索を有効にするには、次の手順に従います。

  1. Azure Cosmos DB for NoSQL リソース ページに移動します。
  2. 左側のウィンドウの [設定] で、[ 機能] を選択します。
  3. NoSQL API のベクター検索を選択します。
  4. 機能の説明を読んで、有効にすることを確認します。
  5. [ 有効にする] を 選択して、Azure Cosmos DB for NoSQL でベクター検索を有効にします。

ヒント

または、Azure CLI を使用してアカウントの機能を更新し、Azure Cosmos DB for NoSQL ベクター検索をサポートします。

az cosmosdb update \
     --resource-group <resource-group-name> \
     --name <account-name> \
     --capabilities EnableNoSQLVectorSearch

登録要求は自動的に適用されますが、有効になるまでに 15 分かかる場合があります。

次の手順では、 Azure Cosmos DB for NoSQL アカウントを設定し、データベースを作成する方法を把握していることを前提としています。 ベクター検索機能は、現在、既存のコンテナーではサポートされていません。 新しいコンテナーを作成する必要があります。 コンテナーを作成するときは、コンテナー レベルのベクター埋め込みポリシーとベクター インデックス作成ポリシーを指定します。

インターネットベースの書店のデータベースを作成する方法の例を見てみましょう。 各書籍のタイトル、作成者、ISBN、および説明情報を格納する必要があります。 また、ベクター埋め込みを含めるために、次の 2 つのプロパティを定義する必要があります。

  • contentVector プロパティには、書籍のテキスト コンテンツから生成されたテキスト埋め込み文字列が含まれています。 たとえば、埋め込みを作成する前に、 titleauthorisbn、および description のプロパティを連結します。
  • coverImageVectorプロパティは、書籍の表紙の画像から生成されます。

ベクター検索を実行するには、次の操作を行います。

  1. ベクトル検索を実行するフィールドのベクトル埋め込みを作成し、保存します。
  2. ベクトル埋め込みポリシーでベクトル埋め込みパスを指定します。
  3. コンテナーのインデックス作成ポリシーに必要なベクター インデックスを含めます。

この記事の以降のセクションでは、コンテナーに格納されている項目の次の構造を検討してください。

{
  "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 クエリ エンジンに通知する情報を提供します。 このポリシーは、ベクター インデックス作成ポリシーを指定する場合に必要な情報も提供します。

コンテナー ベクター ポリシーには、次の情報が含まれています。

パラメーター Description
path ベクトルを含むプロパティ パス。
datatype ベクターの要素の型。 既定値は Float32です。
dimensions パス内の各ベクターの長さ。 既定値は 1536です。
distanceFunction 距離/類似性の計算に使用されるメトリック。 既定値は Cosineです。

書籍の詳細を含む例では、ベクター ポリシーは次の例のようになります。

// 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 に追加しないと、ベクトル挿入の要求ユニットにかかる料金とレイテンシーが高くなります。

ベクター類似性検索クエリを実行する

必要なベクター ポリシーを使用してコンテナーを作成し、ベクター データをコンテナーに挿入した後、クエリで VectorDistance システム関数を使用してベクター検索を実行します。

説明を見て、食品のレシピに関する書籍を検索するとします。 まず、あなたのクエリテキストのための埋め込みを取得する必要があります。 この場合、クエリ テキスト 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()));
  }