• 關於 Milvus
  • 開始使用
  • 概念
  • 使用者指南
  • 資料匯入
  • AI 工具
  • 管理指南
  • 工具
  • 整合功能
  • 教學指南
  • 常見問題
  • API Reference

使用 SVS Vamana 和 Milvus 進行搜尋

SVS(可擴展向量搜尋)是英特爾(Intel)的一套高效能向量搜尋函式庫,實作 Vamana 圖演算法。 在 Milvus 中,您可以透過FAISS 索引穿透機制存取 SVS Vamana:將 `index_type ` 設定為 `FAISS `,並提供 `SVSVamana ` 索引建構字串,Milvus 便會透過 FAISS 的 SVS 整合功能來建立並搜尋索引。

Vamana 是DISKANN亦採用的圖結構,但 SVS Vamana 會將整個圖結構保存在記憶體中。它還能透過LeanVec或LVQ 壓縮向量,藉此減少記憶體使用量並加速搜尋,同時仍能達到極高的召回率。

先決條件

  • Milvus 3.0.0 或更新版本,需從原始碼編譯且已啟用 SVS
  • PyMilvus 3.0.0 或更新版本
  • 若使用LVQ* 或LeanVec* 儲存方案,則需 Intel CPU;FP32 、FP16 及SQ8 儲存方案可在任何平台上運行
  • 熟悉FAISS 索引工廠字串

SVS 未包含在 Milvus 的預設建置中。若要使用SVSVamana 工廠,請透過make USE_SVS=ON 從原始碼建置 Milvus。在未包含 SVS 的建置中,索引建置會失敗,因為 Faiss 無法識別該工廠字串。

LVQ 和 LeanVec 壓縮僅能在 Intel CPU 上執行,且在具備 AVX-512 的 CPU 上執行速度更快。在其他 CPU 上,使用LVQ* 和LeanVec* 工廠字串時,索引建置會失敗。

SVS Vamana 的運作原理

Vamana 圖

SVS Vamana 會建構一個單層鄰近圖。每個向量皆為一個節點,而邊則連接可能為近鄰的向量。為了建構此圖,SVS 會針對每個節點x 執行以下步驟:

  1. 貪婪搜尋:SVS 會搜尋目前已建構的圖,並維持一個大小為construction_window_size 的候選清單。

  2. 鄰居修剪:已造訪的節點將成為x 的候選鄰居。SVS 會依照這些節點與x 之間距離由小到大的順序進行考量。 若已保留的更近鄰節點n 滿足alpha * distance(n, c) <= distance(x, c) ,則跳過候選節點c 。此機制可保留長程邊並刪除冗餘的短程邊,使搜尋能跨越圖結構,而非逐個最近鄰節點地移動。當圖的度數達到上限時,修剪過程即告終止。

  3. 反向邊:對於x 的每個新鄰居,SVS 會新增一條指向x的反向邊,並在該鄰居的邊清單超過圖的度數時進行修剪。

修剪過程分為兩輪:首先使用alpha = 1 ,接著使用設定的alpha 。較大的圖度與construction_window_size 會產生更密集、品質更高的圖,但會消耗更多記憶體且建構時間較長。

在搜尋階段,SVS 會貪婪地遍歷圖,並保留迄今為止觀察到的、距離查詢最近的候選節點(search_window_size )。它總是先探索距離最近且尚未造訪的候選節點。當當前節點的所有鄰居與查詢節點的距離,均比視窗內最差候選節點與查詢節點的距離更遠時,搜尋即告結束。較大的search_window_size 會探索更多圖的區域,這雖能提高召回率,但也會增加延遲。

LeanVec 壓縮

LeanVec同時減少了每個向量的維數以及每維的位元數。LeanVec 索引會為每個向量保存兩種表示形式:

  • 主要表示(降維):將向量線性投影至較低維度的表示。圖搜尋在這個主要資料集上執行,因此大部分的距離計算都在低維空間中進行。這同時降低了運算和記憶體頻寬的需求。預設情況下,降維後的維度為原始維度的一半(dim / 2 )。

  • 次要表示(全維度):向量在原始維度下的表示。SVS 會根據此次要資料集,對主要圖搜尋所返回的候選項進行重新排序,以彌補因維度縮減而損失的準確度。

這兩種表示形式均採用LVQ(局部自適應向量量化)進行量化。工廠字串中的儲存組件負責選取編碼方式。例如,LeanVec4x8 對主要資料集採用每維度 4 位元,對次要資料集則採用每維度 8 位元。即使是重新排序步驟,也絕不會讀取全精度向量。

預設情況下,LeanVec 會分別為索引向量和查詢學習獨立的投影,以支援來自與索引向量不同分佈的查詢(即「分佈外」或 OOD)。 此機制對於跨模態工作負載(例如文字到影像檢索)特別有效,且當查詢來自與索引向量相同的分佈時,同樣表現良好。Milvus 目前尚不支援將查詢傳遞以計算投影,因此現階段僅使用基礎向量。OOD 訓練會增加建置時間。 若希望以犧牲部分查詢效能為代價來加快建置速度,請將 `ood_training ` 設定為 `False`。

LVQ 壓縮

對於維度少於約 512 維的資料集,跳過維度縮減並僅使用 LVQ 量化進行壓縮,效果可能更佳。 與 LeanVec 類似,LVQ 索引會保留一個用於快速搜尋的主表示,以及一個用於重新排序的殘差表示。例如,LVQ4x4 會使用 4 位元作為主表示,並使用 4 位元作為殘差表示。LVQ4x0 和LVQ8x0 會跳過重新排序步驟,若其召回率足以滿足您的工作負載需求,此舉可加快查詢速度。

選擇工廠字串

SVS Vamana 的工廠字串格式為SVSVamana<degree>[,<storage>] ,其中<degree> 代表圖中每個節點的最大邊數。

預設字串儲存備註
SVSVamana64FP32未壓縮向量。
SVSVamana64,FP1616 位元浮點數僅需FP32 一半的向量記憶體,且精度損失極小。
SVSVamana64,SQ88 位元標量量化僅需FP32 四分之一的向量記憶體。
SVSVamana64,LVQ4x0,LVQ8x0LVQ 為主,無殘差僅限 Intel CPU。不進行重新排序。
SVSVamana64,LVQ4x4,LVQ4x8LVQ 主要演算法與殘差僅限 Intel CPU。
SVSVamana64,LeanVec4x4,LeanVec4x8,LeanVec8x8LeanVec 主要與次要僅限 Intel CPU。請添加_<dim> 後綴以設定降維維度。例如,LeanVec4x8_128 會將主要資料集降維至 128 維。若未添加後綴,降維維度將為dim / 2 。

SVSVamana64,LeanVec4x8 這是一個不錯的起點。在此基礎上:

  • 若要在犧牲部分記憶體空間的前提下提升召回率,請使用_<dim> 後綴來增加 LeanVec 的維度。

  • 若需在犧牲部分召回率的前提下縮小記憶體佔用,請降低 LeanVec 的維度。

  • 對於低維向量,請嘗試使用LVQ8 。

  • 在非 Intel CPU 上,請使用FP16 或SQ8 。

建立索引

以下範例建立一個圖度為 64 且採用 LeanVec 壓縮的 SVS Vamana 索引。請展開設定區塊並在建立索引前執行該區塊。

準備資料集

import random

from pymilvus import DataType, MilvusClient

client = MilvusClient(uri="http://localhost:19530")
collection_name = "svs_vamana_example"

if client.has_collection(collection_name):
    client.drop_collection(collection_name)

rng = random.Random(42)
vectors = [[rng.random() for _ in range(256)] for _ in range(3000)]

schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field("id", DataType.INT64, is_primary=True)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=256)

client.create_collection(collection_name=collection_name, schema=schema)

client.insert(
    collection_name=collection_name,
    data=[{"id": i, "vector": vector} for i, vector in enumerate(vectors)],
)
client.flush(collection_name=collection_name)

將 `index_type ` 設定為 `FAISS`,並使用 `faiss_index_name ` 選取 SVS Vamana 配方。

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="vector",
    index_name="svs_vamana_index",
    index_type="FAISS",
    metric_type="L2",
    params={
        # SVSVamana64 -> Vamana graph degree 64
        # LeanVec4x8  -> 4-bit primary, 8-bit secondary
        # _128        -> LeanVec dim 128 (omit the suffix for dim / 2)
        "faiss_index_name": "SVSVamana64,LeanVec4x8_128",
        "construction_window_size": 200,  # build-time search width
        "ood_training": True,             # OOD on (default)
    },
)

client.create_index(collection_name=collection_name, index_params=index_params)
client.load_collection(collection_name=collection_name)

搜尋索引

search_window_size 此參數控制召回率與延遲之間的權衡,如同HNSW 中的 `ef ` 所做的那樣。請將 `search_buffer_capacity ` 設定為至少與該值相同。兩者的預設值皆為 10,且若 `search_window_size ` 大於其 `search_buffer_capacity`,SVS 將拒絕該搜尋請求。

search_params = {
    "params": {
        "search_window_size": 100,      # wider = higher recall, lower QPS
        "search_buffer_capacity": 100,  # must be >= search_window_size
    }
}

res = client.search(
    collection_name=collection_name,
    data=[vectors[0]],
    anns_field="vector",
    limit=10,
    search_params=search_params,
)

若limit 大於search_window_size ,SVS 會將該次搜尋的視窗大小調高至limit 。

SVS Vamana 參數

以下建置參數應置於params 中的add_index() 內,位於faiss_index_name 旁邊。索引建置完成後,您將無法變更這些參數。

參數預設值說明
construction_window_size40在圖構造過程中,用於查找各節點鄰居的候選清單大小。較大的數值可提升圖的品質與召回率,但建構時間會較長。請將其設定為至少等於圖的度數。200 是常見的選擇。
alpha1.2 針對L2 ,請參閱0.95 ;針對IP ,請參閱COSINE修剪強度。數值越遠離 1,修剪越激進,傾向保留長程邊而非冗餘的短程邊。針對L2 ,請使用大於 1 的數值;針對IP 和COSINE ,則使用小於 1 的數值。除非您已針對自身資料測量出更佳的數值,否則請維持預設值。
graph_max_degree工廠字串中的度數,或32每個節點的最大邊數。此設定會覆寫工廠字串中的度數。數值範圍 [32, 128] 適用於大多數工作負載。較高的數值可提高召回率,但會消耗更多記憶體且建構時間較長。
prune_to圖的度數減去 4當節點超過圖的度數時,經過一次修剪後保留的邊數。
max_candidate_pool_size200修剪節點鄰居時所考慮的候選節點最大數量。此數值應大於construction_window_size 。
use_full_search_historyTrue修剪時是否會考慮建構搜尋過程中造訪過的每個節點,而不僅限於最終候選節點。
leanvec_d_<dim> 預設字串後綴或dim / 2僅限 LeanVec。主要資料集的降維係數。此參數會覆寫預設字串後綴。較小的數值可減少記憶體使用量並加快圖搜尋速度,但會降低召回率。
ood_trainingTrue 適用於 LeanVec僅限 LeanVec。是否為索引向量與查詢分別學習投影。若要加快建構速度,請將 `False ` 設為 `true`。若將 `True ` 設定為 LeanVec 以外的任何預設值,設定將失敗。

以下搜尋參數應設定於 `search_params.params` 中。您亦可將其設為建置參數,此舉將變更索引在未設定這些參數的搜尋中使用的預設值。

參數預設值說明
search_window_size10遍歷圖時保留的最接近候選項數量。較大的數值會提高召回率並增加延遲。
search_buffer_capacity10搜尋緩衝區的容量。必須大於或等於search_window_size 。在大多數情況下,請將其設定為search_window_size 。對於 LeanVec,請嘗試設定為search_window_size 的 1.5 倍。

進一步了解

  • 請參閱FAISS 索引直通參考文件,了解一般工廠字串合約、限制及錯誤處理。
  • 與DISKANN 中的磁碟上 Vamana 實作進行比較。
  • 請參閱SVS 儲存庫,了解建置細節、效能調校以及底層的 C++ API。

翻譯者DeepL

免費嘗試托管的 Milvus

Zilliz Cloud 無縫接入,由 Milvus 提供動力,速度提升 10 倍。

開始使用
反饋

這個頁面有幫助嗎?