kNN 检索是干什么的
Elasticsearch 8.x 支持把向量字段建成可检索索引,再按向量相似度做最近邻查询:映射里声明 dense_vector 类型并开启 index,查询时用 knn 参数给出查询向量、返回条数 k 与候选集大小 num_candidates。这样语义召回与传统全文检索就能放在同一条查询链路里。
近似检索的含义
带索引的向量检索走的是近似算法(图结构索引),目标是高概率召回而不是精确的前 k 名。num_candidates 决定每个分片先取多少候选,再由协调节点归并出前 k 条:值越大召回率越高、计算与内存开销越大。k 只决定最终返回条数,两者作用不同,不能互相替代。
基本信息
| 映射 | "type": "dense_vector", "dims": N, "index": true, "similarity": "cosine" |
|---|---|
| 查询 | "knn": { "field": ..., "query_vector": [...], "k": 10, "num_candidates": 100 } |
| 混合检索 | knn 与 query 同时出现时各自算分,用 boost 调权重 |
| 相似度 | cosine、dot_product、l2_norm 需与向量生成方式匹配 |
| 适用版本 | Elasticsearch 8.x 提供带索引的向量检索 |
示例
示例
PUT /my-vectors
{
"mappings": {
"properties": {
"title": { "type": "text" },
"image-vector": { "type": "dense_vector", "dims": 3, "index": true, "similarity": "l2_norm" }
}
}
}
GET /my-vectors/_search
{
"knn": { "field": "image-vector", "query_vector": [0.1, 2.3, -5.0], "k": 10, "num_candidates": 100 },
"fields": ["title"],
"_source": false
}
# 混合检索:关键词与向量两路各自算分,用 boost 调权重
GET /my-vectors/_search
{ "query": { "match": { "title": "风景" } }, "knn": { "field": "image-vector", "query_vector": [0.1, 2.3, -5.0], "k": 10, "num_candidates": 50, "boost": 0.5 } }典型使用场景
- 语义检索:用向量召回语义相近的文档,弥补关键词匹配的不足
- 以图搜图或相似商品推荐
- 混合检索:关键词与向量得分加权,兼顾精确与泛化
- 去重与聚类:找出与目标样本最接近的若干条目
- 检索增强生成:按向量召回最相关的文档片段作为上下文
关键参数的作用
| 参数 | 作用 | 调大后的影响 |
|---|---|---|
| k | 最终返回条数 | 返回更多,端到端耗时略增 |
| num_candidates | 每个分片的候选集大小 | 召回更高,计算与内存开销上升 |
| similarity | 相似度算法 | 与向量生成方式不一致会让排序失去意义 |
| boost | knn 与 query 的分数权重 | 用于平衡关键词与向量两路得分 |
查询向量的维度必须与映射 dims 完全一致,不符会直接报错;向量维度高、文档量大时索引占用的内存与磁盘都不小,上线前先做容量评估。
dense_vector 开索引与不开索引行为不同:不开索引只能用脚本计算相似度,无法使用 knn 查询;similarity 一旦确定,改算法通常要重建索引。