1. kNN retriever 是什么?
kNN retriever
是 Retriever 框架中的首階段召回器,負責對一個向量字段做近鄰搜索,返回 Top-K 文檔。相比早期的 knn
頂級語法,Retriever 讓我們能在一個請求里組合多種策略(如 RRF/Rescorer/Linear/Rule 等),把復雜的檢索流程收斂到單次 API 調用。
最小示例:
GET /restaurants/_search
{"retriever": {"knn": {"field": "vector", // dense_vector 且開啟 indexing"query_vector": [10, 22, 77],"k": 10, // 返回的近鄰數量"num_candidates": 10 // 每個分片候選集大小(≥ k)}}
}
2. 必備前提
field
必須是dense_vector
且開啟 indexing(支持近似向量檢索)。query_vector
維度必須與字段一致;
或者用query_vector_builder
(由模型在線生成查詢向量),二者不可同用。- 適配 Serverless/Stack 的 Retriever 語法(8.16+ 普遍 GA,細節隨版本演進)。
3. 核心參數詳解與實戰建議
3.1 field
(必填)
向量字段名。
建議:為該字段單獨配置合適的近似索引(例如 HNSW 的 M/efConstruction),以平衡召回率與延遲。
3.2 query_vector
/ query_vector_builder
(二選一)
query_vector
:直接傳浮點數組或十六進制字節(與字段維度一致)。query_vector_builder
:在查詢期由模型構建向量(適合服務化 embedding)。
選擇指南:
- 線上 RAG/檢索場景通常預先 embed,性能更穩;
- 想用統一模型推理與多模態輸入時,考慮
query_vector_builder
。
3.3 k
(必填)
最終返回的 Top-K。
經驗值:終端排序/重排還會繼續“洗牌”,k
設得略大于展示位(如展示 10,可取 50~100)更穩。
3.4 num_candidates
(必填/有默認)
每分片候選集大小,≥ k
(或當未顯式 k
時 ≥ size
),且 ≤ 10000
。
默認:min(1.5 * k, 10_000)
。
調優要點:
- 更大的
num_candidates
? 更高召回與更準 Top-K,但延遲與內存占用上升; - 多分片時是分片級采樣:每個分片都先取
num_candidates
,合并后再出全局 Top-K。
3.5 filter
(可選:單個或數組)
在向量檢索前先用結構化/倒排過濾:
- 限定類目、狀態、時間、地理范圍等;
- 只有通過過濾的文檔才進入 kNN 候選與排序。
建議:盡量把能過濾的條件都放進來,先減集合后做向量檢索,性能與相關性都會更好。
3.6 similarity
(可選:浮點)
直接作用于“向量相似度”本體的閾值,不同度量解釋不同:
l2_norm
(歐氏距離):半徑閾值,僅返回在“半徑=similarity”的超球體內的向量;值越小越嚴格。cosine
/dot_product
/max_inner_product
:只返回相似度 ≥ similarity 的向量;值越大越嚴格。
和最終
_score
的區別:similarity
是原始向量相似度的門檻;命中后文檔還會按 similarity 計分并應用 boost,然后進入 Top-K。
調參技巧:
- 若召回太多噪聲,適當提高
cosine
/dot_product
的閾值; - 用
l2_norm
時注意尺度(embedding 是否歸一化)。
4. 進階:量化向量的重排(rescore_vector
)
版本:Stack 9.1.0(9.0.0 為 preview)
僅對量化后的 dense_vector 有意義;非量化字段會忽略該項。
動機:量化索引的近似搜索極快,但初始得分可能受量化誤差影響。
方案:先用近似索引取候選,再用原始向量對更小集合做精排。
配置項:
-
oversample
(必填,浮點):對k
做過采樣倍率。工作流:- 按近似索引取
num_candidates
; - 選出
k * oversample
個候選,用原始向量重算相似度; - 取重算后的 Top-K 作為最終結果。
- 按近似索引取
經驗值:oversample
取 2.0~4.0 常見。過大提升有限但開銷明顯;建議壓測找平衡點。
5. 組合示例
5.1 kNN + 過濾(類目 & 地理)
GET /poi/_search
{"retriever": {"knn": {"field": "embedding","query_vector": [/* 768 dims */],"k": 50,"num_candidates": 500,"filter": [{ "term": { "category": "restaurant" } },{ "range": { "rating": { "gte": 4.0 } } },{ "geo_distance": { "distance": "5km", "location": { "lat": 37.78, "lon": -122.42 } } }],"similarity": 0.7 // 僅對 cosine/dot_product 有意義;舉例值}}
}
5.2 量化向量 + 過采樣重排
GET /docs/_search
{"retriever": {"knn": {"field": "emb_q8", // 量化后的 dense_vector"query_vector": "0A0B0C...", // 也可用 hex 向量"k": 20,"num_candidates": 400,"rescore_vector": {"oversample": 3.0 // 先取 60 再用原始向量精排出最終 20}}}
}
5.3 與其他 Retriever 組合(示意)
- 首階段:
knn
召回語義近鄰 - 另一支:
standard
倒排匹配(BM25 / multi_match) - 融合:
rrf
/linear
- 二階段:
rescorer
(可接 LTR / 語義 re-ranker)
組合寫法見 Retriever 文檔,這里不贅述。把 kNN 放進統一管線的收益,就是一次請求完成多路召回與融合。
6. 調優清單(Checklist)
- 字段準備:
dense_vector
+ 索引參數合理(HNSW 的 M/ef*)。 - 維度一致:
query_vector
與字段維度嚴格對齊。 - 候選規模:
num_candidates
=k
的 10~30 倍起步,根據延遲預算逐步調大。 - 過濾優先:能過濾先過濾(類目/狀態/時間/地理/安全域),縮小向量檢索集合。
- 相似度閾:合理用
similarity
做噪聲門檻(尤其cosine/dot_product
)。 - 量化精排:量化場景開啟
rescore_vector
,用oversample
控誤差。 - 多分片意識:Top-K 是全局合并,
num_candidates
是分片級采樣。 - 觀測:記錄 took、候選規模、最終 k、命中率與點擊/轉化,形成離線-在線閉環。
7. 常見報錯與排查
illegal_argument_exception: dimensions mismatch
→ 檢查向量維度;embedding 模型升級后維度變化是高頻來源。num_candidates too small
/k > num_candidates
→ 調整參數,滿足約束(且≤ 10000
)。- 結果偏“飄”(語義不穩)
→ 提高num_candidates
、設置similarity
、或在量化場景開啟rescore_vector
。 - 延遲過高
→ 降低num_candidates
、先做更嚴格filter
、或優化向量索引參數(M/efConstruction)。
8. 小結
kNN retriever
把向量近鄰召回收斂進統一的檢索管線,與倒排、RRF/LTR/Rescorer 等協同非常自然;- 三要素:候選規模(num_candidates)、過濾(filter)、相似度閾(similarity);
- 量化場景配上
rescore_vector.oversample
,在準確度與延遲之間找最優點。