你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

使用 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. 在 Azure Cosmos DB for NoSQL 中选择矢量搜索
  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 帐户并创建数据库。 现有容器当前不支持矢量搜索功能。 需要创建新的容器。 创建容器时,可以指定容器级矢量嵌入策略和矢量索引策略。

让我们以一个示例为例,了解如何为基于 Internet 的书店创建数据库。 你想要存储每本书的标题、作者、ISBN 和说明信息。 还需要定义以下两个属性来包含矢量嵌入:

  • contentVector 属性包含从书籍的文本内容生成的 文本嵌入 。 例如,在创建嵌入之前连接 titleauthorisbndescription 属性。
  • 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()));
  }