共用方式為


.NET 中適用於 NoSQL 的 Azure Cosmos DB 中的索引和查詢向量

本文將逐步引導您完成如何建立向量數據、編製數據的索引,然後查詢容器中的數據的程式。

使用向量索引和搜尋之前,您必須先在適用於 NoSQL 的 Azure Cosmos DB 中啟用向量搜尋。 設定向量搜尋的 Azure Cosmos DB 容器之後,您可以建立向量內嵌原則。 接下來,您將向量索引新增至容器索引政策。 然後,您可以建立具有向量索引和向量內嵌政策的容器。 最後,您會對儲存的數據執行向量搜尋。

先決條件

啟用該功能

若要啟用適用於 NoSQL 的 Azure Cosmos DB 向量搜尋,請遵循下列步驟:

  1. 移至適用於 NoSQL 的 Azure Cosmos DB 資源頁面。
  2. 在左窗格的 [設定] 底下,選取 [功能]。
  3. 在適用於 NoSQL 的 Azure Cosmos DB 中選取 [向量搜尋]。
  4. 閱讀該功能的說明以確認您要啟用它。
  5. 選取 [啟用] 以在適用於 NoSQL 的 Azure Cosmos DB 中開啟向量搜尋。

小提示

或者,使用 Azure CLI 來更新帳戶的功能,以支援適用於 NoSQL 的 Azure Cosmos DB 向量搜尋。

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

註冊要求會自動核准,但可能需要 15 分鐘才能生效。

下列步驟假設您知道如何 設定適用於 NoSQL 的 Azure Cosmos DB 帳戶並建立資料庫。 現有容器目前不支援向量搜尋功能。 您需要建立一個新容器。 建立容器時,您可以指定容器層級向量內嵌政策和向量索引政策。

讓我們舉個例子,說明如何為基於互聯網的書店創建數據庫。 您想要儲存每本書的標題、作者、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] 
} 

為您的容器建立向量內嵌政策

現在您需要定義容器向量政策。 此原則提供可用來通知 Azure Cosmos DB 查詢引擎如何處理系統函式中的 VectorDistance 向量屬性的資訊。 如果您選擇指定一個索引政策,此政策也會提供向量索引政策所需的必要資訊。

下列資訊包含在容器向量原則中:

參數 Description
path 包含向量的屬性路徑。
datatype 向量元素的型別。 (預設值為 Float32。)
dimensions 路徑中每個向量的長度。 (預設值為 1536。)
distanceFunction 用來計算距離/相似性的計量。 (預設值為 Cosine。)

對於具有書籍詳細資訊的範例,向量政策可能類似下列範例:

  Database db = await client.CreateDatabaseIfNotExistsAsync("vector-benchmarking");
  List<Embedding> embeddings = new List<Embedding>()
  {
      new Embedding()
      {
          Path = "/coverImageVector",
          DataType = VectorDataType.Float32,
          DistanceFunction = DistanceFunction.Cosine,
          Dimensions = 8,
      },
      new Embedding()
      {
          Path = "/contentVector",
          DataType = VectorDataType.Float32,
          DistanceFunction = DistanceFunction.Cosine,
          Dimensions = 10,
      }
  };

在索引原則中建立向量索引

決定向量內嵌路徑之後,您必須將向量索引加入至索引政策。 目前,只有新容器支援適用於 NoSQL 的 Azure Cosmos DB 向量搜尋功能。 當您建立容器時,您會套用向量政策。 您稍後無法修改原則。 索引原則看起來類似下列範例:

    Collection<Embedding> collection = new Collection<Embedding>(embeddings);
    ContainerProperties properties = new ContainerProperties(id: "vector-container", partitionKeyPath: "/id")
    {   
        VectorEmbeddingPolicy = new(collection),
        IndexingPolicy = new IndexingPolicy()
        {
            VectorIndexes = new()
            {
                new VectorIndexPath()
                {
                    Path = "/vector",
                    Type = VectorIndexType.QuantizedFlat,
                }
            }
        },
    };
    properties.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });    
    properties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/vector/*" });

這很重要

向量路徑將被新增至索引原則的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])   

此查詢會擷取書籍標題,以及與查詢有關的相似度分數。 以下是 .NET 中的範例:

  float[] embedding = {1f,2f,3f,4f,5f,6f,7f,8f,9f,10f};
  var queryDef = new QueryDefinition(
      query: $"SELECT c.title, VectorDistance(c.contentVector,@embedding) AS SimilarityScore FROM c ORDER BY VectorDistance(c.contentVector,@embedding)"
      ).WithParameter("@embedding", embedding);
  using FeedIterator<Object> feed = container.GetItemQueryIterator<Object>(
      queryDefinition: queryDef
  );
  while (feed.HasMoreResults) 
  {
      FeedResponse<Object> response = await feed.ReadNextAsync();
      foreach ( Object item in response)
      {
          Console.WriteLine($"Found item:\t{item}");
      }
  }