目录
- 向量检索的背景与kNN问题简介
- Elasticsearch中两种kNN搜索方式概览
- 精确kNN搜索原理与实现
- 近似kNN搜索(ANN)原理与实现
- 性能对比:精确 vs 近似
- 场景选择建议与常见误区
- 精确kNN实战:代码 + 配置示例
- ANN实战:HNSW配置 + 查询参数讲解
- 总结与最佳实践建议
1. 向量检索的背景与kNN问题简介
1.1 什么是kNN搜索?
kNN(k-Nearest Neighbors) 问题:给定查询向量 $q$,在数据库中寻找与其最相近的 $k$ 个向量 $x\_i$,常用相似度包括:
- 余弦相似度(cosine)
- 欧式距离(l2)
- 内积(dot product)
kNN广泛应用于:
- 语义搜索(semantic search)
- 图像/视频检索
- RAG(Retrieval-Augmented Generation)
- 推荐系统中的embedding匹配
2. Elasticsearch中两种kNN搜索方式概览
Elasticsearch 8.x 原生支持以下两种向量搜索模式:
模式 | 描述 | 搜索方式 | 索引类型 |
---|
精确kNN | 遍历所有向量,逐个计算相似度 | 线性搜索(Brute-force) | dense_vector (未启用 index) |
近似kNN | 通过图结构等索引加速查找 | ANN(如 HNSW) | dense_vector (启用 index) |
3. 精确kNN搜索原理与实现
3.1 搜索机制
遍历整个索引中的向量字段,逐一计算与查询向量的相似度,并返回得分最高的前 $k$ 个:
伪代码:
for vec in all_vectors:
score = cosine_similarity(query, vec)
update_top_k(score)
3.2 特点
优点 | 缺点 |
---|
100% 精度 | 性能差,O(n) 计算复杂度 |
数据更新无影响 | 不适合大规模索引(>10W 向量) |
无需构建图结构索引 | 查询耗时可能>秒级 |
4. 近似kNN搜索(ANN)原理与实现
Elasticsearch 使用 HNSW(Hierarchical Navigable Small World) 图实现 ANN 索引:
- 构建一个多层次图;
- 查询时从高层开始跳转,快速找到接近节点;
- 在底层做精细扫描。
4.1 原理图示(文字描述)
Level 2: [A]---[B]
| |
Level 1: [C]---[D]---[E]
| |
Level 0: [F]---[G]---[H]---[I]
- 查询从高层的B开始,逐层“爬”向更近点;
- 最终在底层局部区域中进行精细比较。
4.2 特点
优点 | 缺点 |
---|
查询极快(ms 级) | 精度小于 100%,依赖调优参数 |
可扩展到百万/千万向量 | 构建索引耗时,需占内存 |
支持复杂相似度 | 数据变更需重建索引 |
5. 性能对比:精确 vs 近似
指标 | 精确kNN | 近似kNN(HNSW) |
---|
精度 | 100% | 95\~99%(可调) |
查询时间 | 慢(线性) | 快(ms 级) |
内存占用 | 低 | 中\~高 |
构建时间 | 无 | 有(建图) |
更新代价 | 低(直接写入) | 高(需重建) |
向量数量推荐 | < 1 万 | > 1 万 |
6. 场景选择建议与常见误区
6.1 使用精确kNN的场景
- 数据量小(<10,000)
- 对结果要求严格(如 AI训练集回溯)
- 数据频繁变更(如在线更新)
- 临时验证或研发环境
6.2 使用近似kNN的场景
- 数据量大(>100,000)
- 查询性能关键(<100ms 延迟)
- 构建 RAG / 向量搜索服务
- 可接受部分精度损失
6.3 常见误区
误区 | 正确做法 |
---|
近似搜索不准不能用 | 调整 num_candidates 提升召回 |
精确搜索总是最好的 | 面对大量数据时严重性能瓶颈 |
不配置向量字段也能跑kNN | 必须设置 dense_vector 类型并使用正确参数 |
7. 精确kNN实战:代码 + 配置示例
7.1 映射配置
PUT /exact-knn-index
{
"mappings": {
"properties": {
"text": { "type": "text" },
"embedding": {
"type": "dense_vector",
"dims": 384
}
}
}
}
7.2 写入数据
es.index(index="exact-knn-index", body={
"text": "这是一段文本",
"embedding": embedding.tolist()
})
7.3 查询示例
POST /exact-knn-index/_search
{
"size": 3,
"query": {
"script_score": {
"query": { "match_all": {} },
"script": {
"source": "cosineSimilarity(params.query_vector, doc['embedding']) + 1.0",
"params": { "query_vector": [0.1, 0.2, ...] }
}
}
}
}
8. ANN实战:HNSW配置 + 查询参数讲解
8.1 HNSW 索引映射
PUT /ann-index
{
"mappings": {
"properties": {
"embedding": {
"type": "dense_vector",
"dims": 384,
"index": true,
"similarity": "cosine",
"index_options": {
"type": "hnsw",
"m": 16,
"ef_construction": 128
}
}
}
}
}
8.2 写入数据(与精确方式相同)
es.index(index="ann-index", body={
"text": "RAG 搜索是未来主流",
"embedding": vector.tolist()
})
8.3 查询近似向量
POST /ann-index/_search
{
"knn": {
"field": "embedding",
"query_vector": [0.2, 0.3, ...],
"k": 5,
"num_candidates": 100
}
}
参数说明:
参数 | 含义 |
---|
k | 返回最近的 k 个结果 |
num_candidates | HNSW搜索时扫描的候选节点数(越大越准) |
m | 每个节点连接的邻居数 |
ef_construction | 索引构建时的搜索宽度 |
9. 总结与最佳实践建议
维度 | 精确 kNN | 近似 kNN(HNSW) |
---|
精度 | 完全准确 | 可调(95\~99%) |
查询速度 | 慢 | 快(ms 级) |
构建复杂度 | 无 | 中等(建图) |
更新灵活性 | 高 | 低(不可局部更新) |
推荐使用 | 小规模、高精度 | 大规模、在线服务 |
最佳实践建议:
- 实验阶段优先使用精确搜索,利于调试;
- 生产阶段建议使用近似搜索,节省资源;
- 向量量小于 5 千:精确优先;
- 向量量大于 5 万:HNSW 必选;
- 对精度要求特别高时:调大
num_candidates
; - 不要忘记对向量归一化(Cosine similarity 场景);
评论已关闭