本文指导你完成如何创建矢量数据、为数据编制索引,然后查询容器中的数据的过程。
在使用矢量索引和搜索之前,必须先在 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 Python SDK。
 
启用功能
若要为 Azure Cosmos DB for NoSQL 启用矢量搜索,请执行以下步骤:
- 转到 Azure Cosmos DB for NoSQL 资源页。
 - 在左窗格中的 “设置”下,选择“ 功能”。
 - 在 Azure Cosmos DB for NoSQL 中选择矢量搜索。
 - 阅读该功能的说明以确认要启用该功能。
 - 选择 “启用” 以在 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 和说明信息。 还需要定义以下两个属性来包含矢量嵌入:
- 为要执行矢量搜索的字段创建并存储矢量嵌入。
 - 在矢量嵌入策略中指定矢量嵌入路径。
 - 在容器的索引策略中包含所需的任何向量索引。
 
对于本文的后续部分,请考虑容器中存储的项的以下结构:
{
  "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] 
}
为容器创建矢量嵌入策略
现在需要定义容器向量策略。 此策略提供了用于通知 Azure Cosmos DB 查询引擎如何处理系统函数中的 VectorDistance 向量属性的信息。 如果选择指定一个,此策略还会向向量索引策略提供必要的信息。
容器向量策略中包括以下信息:
| 参数 | DESCRIPTION | 
|---|---|
path | 
包含向量的属性路径。 | 
datatype | 
矢量的元素的类型。 (默认值为 Float32。) | 
dimensions | 
路径中每个向量的长度。 (默认值为 1536。) | 
distanceFunction | 
用于计算距离/相似度的指标。 (默认值为 Cosine。) | 
对于包含书籍详细信息的示例,矢量策略可能如以下示例所示:
vector_embedding_policy = { 
    "vectorEmbeddings": [ 
        { 
            "path": "/coverImageVector", 
            "dataType": "float32", 
            "distanceFunction": "dotproduct", 
            "dimensions": 8 
        }, 
        { 
            "path": "/contentVector", 
            "dataType": "float32", 
            "distanceFunction": "cosine", 
            "dimensions": 10 
        } 
    ]    
} 
在索引策略中创建矢量索引
确定矢量嵌入路径后,必须将向量索引添加到索引策略。 索引策略类似于以下示例:
indexing_policy = { 
    "includedPaths": [ 
        { 
            "path": "/*" 
        } 
    ], 
    "excludedPaths": [ 
        { 
            "path": "/\"_etag\"/?",
            "path": "/coverImageVector/*",
            "path": "/contentVector/*"
            
        } 
    ], 
    "vectorIndexes": [ 
        {"path": "/coverImageVector", 
         "type": "quantizedFlat" 
        }, 
        {"path": "/contentVector", 
         "type": "quantizedFlat" 
        } 
    ] 
} 
重要
将向量路径添加到索引策略的 excludedPaths 节,以确保插入性能的优化。 不将向量路径添加到 excludedPaths 会导致矢量插入的请求单元费用和延迟更高。
目前,新容器仅支持 Azure Cosmos DB for NoSQL 中的矢量搜索。 创建容器时,需要同时设置容器向量策略和任何向量索引策略,因为以后无法对其进行修改。
使用矢量策略创建容器
目前,Azure Cosmos DB for NoSQL 的矢量搜索功能仅在新容器上受支持。 创建容器时,应用向量策略。 以后无法修改策略。
try:     
    container = db.create_container_if_not_exists( 
                    id=CONTAINER_NAME, 
                    partition_key=PartitionKey(path='/id'), 
                    indexing_policy=indexing_policy, 
                    vector_embedding_policy=vector_embedding_policy) 
    print('Container with id \'{0}\' created'.format(id)) 
except exceptions.CosmosHttpResponseError: 
        raise 
运行矢量相似性搜索查询
使用所需的向量策略创建容器并将矢量数据插入容器后,请在查询中使用 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])   
此查询检索书名以及与你的查询相对应的相似度分数。 下面是一个使用 Python 的示例:
query_embedding = [1,2,3,4,5,6,7,8,9,10] 
# Query for items 
for item in container.query_items( 
            query='SELECT c.title, VectorDistance(c.contentVector,@embedding) AS SimilarityScore FROM c ORDER BY VectorDistance(c.contentVector,@embedding)', 
            parameters=[ 
                {"name": "@embedding", "value": query_embedding} 
            ], 
            enable_cross_partition_query=True): 
    print(json.dumps(item, indent=True))