向量檢索服務 Milvus 版(簡稱 Milvus)支援在 DiskANN 索引上執行範圍搜尋。DiskANN 上的範圍搜尋,按 Milvus 範圍搜尋語義執行:以查詢向量為圓心,radius 為外圈,range_filter 為內圈,只保留位於環帶內的向量,再從中返回最相似的前 limit 條。本文介紹這三個參數的配置方法、search_list 的取值建議及預期返回結果。
前提條件
已建立支援 DiskANN 索引的 Milvus 執行個體,詳情請參見快速建立Milvus執行個體。
已準備帶有資料的 Collection,並為待搜尋的向量欄位建立 DiskANN 索引。
已擷取執行個體 Endpoint、使用者名稱和密碼,並確認運行 Python 的環境可訪問該 Endpoint。
已安裝 PyMilvus。
pip install pymilvus阿里雲 DiskANN 的實現和參數可能與開源 Milvus 不同,詳情請參見容量型磁碟索引(DiskANN)。小資料量樣本用於說明參數和返回結果;評估搜尋視窗的調優效果時,應使用接近業務規模的資料。
範圍搜尋原理
指定 radius 的搜尋包含以下三個步驟:
使用集合的度量,按與查詢向量的相似性從近到遠搜尋候選向量。DiskANN 在此步驟中執行圖搜尋,不會遍曆全庫執行暴力檢索。
僅保留距離或得分位於
radius與range_filter之間的向量。從保留的向量中返回最相似的前 K 條。K 為請求中的
limit。
環帶內不足 K 條時,返回條數可以少於 K。limit = 3 時最多返回 3 條,不保證返迴環帶內的全部向量。
預設情況下,過濾和搜尋終止使用原始向量的精確距離:排除比內圈更近的向量並繼續搜尋,保留位於環帶內的向量。當結果達到 K 條,或下一條精確距離達到或超出外圈邊界時,搜尋終止。
度量與不等式
DiskANN 只支援 L2、IP、COSINE 度量距離。
對於距離越小越相似的度量(L2),外圈邊界值大於內圈邊界值:
range_filter <= 距離 < radius對於距離或得分越大越相似的度量(IP、COSINE),外圈邊界值小於內圈邊界值,並且 radius 必須小於 range_filter:
radius < 距離 <= range_filter度量 | 越相似 | 環帶 | 不設內圈時 |
L2 | 距離越小 |
|
|
IP | 得分越大 |
| 省略 |
COSINE | 得分越大 |
| 省略 |
range_filter 設為 0 表示返回半徑內全部實體,適用於 L2 這類距離越小越近的度量。對於 COSINE / IP,將 range_filter 設為 0 會得到 radius < d <= 0 的區間,可能導致結果為空白。例如 COSINE radius = 0.4、range_filter = 0 時,正相似性的向量不滿足該區間條件。內圈為閉區間邊界,外圈為開區間邊界:對於 L2,距離等於 range_filter 時保留,等於 radius 時排除;對於 IP / COSINE,得分等於 range_filter 時保留,等於 radius 時排除。
參數使用
參數 | 作用 | 建議 |
| 外圈 | 根據上表及度量設定,避免與 |
| 內圈。省略表示不設定內圈 | L2 可設為 |
| 最多返回條數,也是搜尋終止條件之一 | 設定為業務所需的 K;增大該值不會擴大半徑 |
| 圖搜尋的候選視窗,控制搜尋廣度 | 取值建議見下一節;該參數不表示每頁結果條數 |
search_list 不限制返回條數。limit = 500、search_list = 100 時,搜尋會繼續沿圖進行,直到擷取 500 條環帶內的結果、精確距離超出外圈,或圖遍曆結束,不會在返回第 100 條結果時終止。未傳入 search_list,或取值小於 100 時,範圍搜尋會將視窗調整為 100。返回條數上限仍為 limit。
推薦使用方法
保留精排
範圍搜尋的過濾和搜尋終止依賴原始向量距離,建議保留預設精排配置:
查詢參數不應設定為
use_refine = false。
根據環帶的近鄰深度設定 search_list
候選視窗應覆蓋目標環帶所在的近鄰深度。配置建議如下:
環帶包含最近鄰(L2 的
range_filter = 0,或 IP / COSINE 省略range_filter):search_list至少取max(100, limit)。limit較小(幾十到一百)時,取值為 100 的召回水平與普通 TopK 相近。內圈排除了較多近鄰,即
range_filter排除了大量最近的向量、目標環帶位於更遠處:應將search_list增大至與目標近鄰深度相同的量級。當視窗僅為 100,而環帶位於數千個近鄰的位置時,圖搜尋往往無法覆蓋環帶,返回結果會偏少。
limit 大於 search_list 時,結果不會被截斷,但候選視窗相對較小,檢索到環帶內第 K 個近鄰的機率會降低。為提高 K 條結果的召回穩定性,應將 search_list 設定為不小於 K。
limit 控制返回條數
limit 表示結果條數上限,不表示搜尋深度。半徑確定搜尋範圍後,增大 limit 只會增加同一環帶內可返回的結果條數,直至環帶內的結果已全部擷取。環帶內只有 10 條時,limit = 1000 仍然只有大約 10 條有效結果,PyMilvus 返回實際命中的結果清單,不會按 limit 補齊結果。
limit 達到 16384 及以上時,範圍搜尋仍執行圖搜尋,不使用 large TopK 掃描路徑。K 較大且環帶較寬時,延遲會明顯增加。業務僅需要幾十條結果時,不建議將 limit 設定為此量級。
返回條數可以少於 limit
以下兩種情況下,返回條數可以少於請求條數:
環帶內的向量數少於
limit。精確距離已超出外圈,後續候選向量的距離更大。
使用 PyMilvus 時,直接遍曆實際返回的命中列表即可,通過 len(res[0]) 統計實際命中數,無需按 limit 預留固定數量的結果。
圖搜尋未覆蓋目標環帶時,返回條數也會偏少。此時應增大 search_list,無需放寬半徑。search_list 與環帶深度處於同一量級時,召回水平與相同視窗的普通 TopK 相近。在此視窗下,估計距離與精確距離之間的少量排序差異,不會使滿足區間條件的結果變為不滿足條件的結果,也不會持續導致整頁結果缺失。
樣本
以下樣本使用已有的 Collection:my_collection_cosine、my_collection_l2、my_collection_ip 分別對應 COSINE、L2、IP 度量的 DiskANN 索引。向量欄位名為 vector,樣本查詢向量為 8 維。請將 Endpoint、憑證、Collection 名稱、向量欄位名和向量維度替換為實際值,並確保搜尋度量與索引一致。
COSINE:檢索得分在 0.4 到 0.6 之間的前 3 條
預設度量是 COSINE 時,radius 必須小於 range_filter。下面的請求返回得分滿足 0.4 < 得分 <= 0.6 的最多 3 條,按得分從高到低。
from pymilvus import MilvusClient
client = MilvusClient(uri="http://<your-endpoint>:19530", token="<your-username>:<your-password>")
query_vector = [
0.3580376395471989,
-0.6023495712049978,
0.18414012509913835,
-0.26286205330961354,
0.9029438446296592,
0.0,
0.0,
0.0,
]
res = client.search(
collection_name="my_collection_cosine",
anns_field="vector",
data=[query_vector],
limit=3,
search_params={
"metric_type": "COSINE",
"params": {
"radius": 0.4,
"range_filter": 0.6,
"search_list": 100,
},
},
)
for hits in res:
for hit in hits:
print(hit["id"], hit["distance"])limit = 3 時,可設定 search_list = 100。若調整為 limit = 200,應將 search_list 設定為不小於 200。
L2:檢索半徑 100 以內的前 10 條,不設定內圈
res = client.search(
collection_name="my_collection_l2",
anns_field="vector",
data=[query_vector],
limit=10,
search_params={
"metric_type": "L2",
"params": {
"radius": 100.0,
"range_filter": 0.0,
"search_list": 100,
},
},
)返回滿足 0 <= 距離 < 100 的最近的最多 10 條結果。
L2:排除近鄰,檢索距離在 20 到 100 之間的結果
res = client.search(
collection_name="my_collection_l2",
anns_field="vector",
data=[query_vector],
limit=10,
search_params={
"metric_type": "L2",
"params": {
"radius": 100.0,
"range_filter": 20.0,
"search_list": 100,
},
},
)返回結果滿足 20 <= 距離 < 100。如果距離小於 20 的近鄰較多,應增大 search_list,使候選視窗能夠覆蓋被內圈排除的近鄰深度。
IP:得分在 0.2 到 0.8 之間
res = client.search(
collection_name="my_collection_ip",
anns_field="vector",
data=[query_vector],
limit=10,
search_params={
"metric_type": "IP",
"params": {
"radius": 0.2,
"range_filter": 0.8,
"search_list": 100,
},
},
)返回滿足 0.2 < 得分 <= 0.8 的得分最高的最多 10 條結果。
結果驗證
返回結果應滿足以下條件:
L2:
range_filter <= distance < radiusIP / COSINE:
radius < distance <= range_filter條數不超過
limit同一條查詢中,L2 結果按距離從小到大排序,IP / COSINE 結果按得分從大到小排序
返回條數少於 limit 時,應檢查區間範圍和 search_list 設定;僅憑這兩項,不能確認已返回區間內的全部向量。
使用注意事項
使用 COSINE / IP 時,應確保
radius和range_filter的大小關係正確;不設定內圈時,應省略range_filter,不應將其設為 0。search_list控製圖搜尋的候選視窗,不表示結果條數;返回條數由limit和環帶內的實際命中數量決定。範圍搜尋中設定
use_refine = false後,將按估計距離過濾環帶邊界,可能降低邊界附近結果的召回率。增大
limit不會擴大搜尋範圍。範圍搜尋不保證返回全庫中位於環帶內的每一個向量。DiskANN 按 ANN 從近到遠擷取前 K 條;受 K 和
search_list限制而未檢索到的遠鄰不會返回。