1. kNN retriever 是什么?
kNN retriever
是 Retriever 框架中的首阶段召回器 ,负责对一个向量字段做近邻搜索 ,返回 Top-K 文档。相比早期的 knn
顶级语法,Retriever 让我们能在一个请求里组合多种策略 (如 RRF/Rescorer/Linear/Rule 等),把复杂的检索流程收敛到单次 API 调用。
最小示例:
http
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 + 过滤(类目 & 地理)
http
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 量化向量 + 过采样重排
http
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
,在准确度与延迟之间找最优点。