【实战ES】实战 Elasticsearch:快速上手与深度实践-8.1.2近似最近邻(ANN)算法选型
👉 点击关注不迷路
👉 点击关注不迷路
👉 点击关注不迷路
文章大纲
- 8.1.2 近似最近邻(ANN)算法选型深度指南
- 1. ANN算法核心原理
- 1.1 主流算法对比矩阵
- 1.2 性能基准(100万128维向量)
- 2. Elasticsearch集成配置
- 2.1 向量索引模板
- 2.2 查询DSL模板
- 3. 算法参数调优
- 3.1 HNSW参数矩阵
- 3.2 IVF优化策略
- 4. 企业级应用案例
- 4.1 电商图像搜索
- 4.2 生物特征识别
- 5. 算法选型决策树
- 6. 未来演进方向
- 6.1 硬件加速方案
- 6.2 算法演进趋势
8.1.2 近似最近邻(ANN)算法选型深度指南
- Elasticsearch向量搜索核心架构与ANN算法集成
近似最近邻(ANN)算法
在高维向量空间中高效近似搜索,解决传统暴力搜索(如余弦相似度计算)在大数据量下计算复杂度高、响应慢的问题
,广泛应用于:- 图像 / 视频检索(如以图搜图)
- 文本语义匹配(如推荐系统)
- 生物信息学(基因序列比对)
1. ANN算法核心原理
1.1 主流算法对比矩阵
算法类型 | 核心原理 | 索引速度 | 查询速度 | 准确率 | 内存消耗 | 适用场景 |
---|---|---|---|---|---|---|
HNSW | 分层图结构(Hierarchical Navigable Small World ),分层可导航小世界 | 中 | 极高 | 95-99% | 高 | 高精度实时搜索 |
IVF(Inverted File Index) | 倒排文件系统(倒排文件 + 聚类中心) | 快 | 快 | 85-95% | 中 | 大规模数据集 |
LSH(Locality Sensitive Hashing) | 局部敏感哈希 | 极快 | 极快 | 60-80% | 低 | 快速近似匹配 |
PQ(Product Quantization) | 乘积量化 | 慢 | 快 | 70-90% | 低 | 高维压缩场景 |
NGT(Non-Graph Tree) | 邻域图遍历 | 慢 | 高 | 90-98% | 高 | 复杂空间关系 |
1.2 性能基准(100万128维向量)
算法 | 索引时间 | 单次查询时间 | 内存占用 | Recall@10 |
---|---|---|---|---|
HNSW(n=32) | 12min | 2.3ms | 4.2GB | 98.7% |
IVF-4096 | 8min | 5.1ms | 2.8GB | 92.3% |
LSH-256bit | 3min | 0.8ms | 1.1GB | 78.5% |
PQ-8x8 | 25min | 1.2ms | 0.9GB | 85.6% |
2. Elasticsearch集成配置
2.1 向量索引模板
// 向 Elasticsearch 发送 PUT 请求,用于创建一个名为 image_vectors 的索引。
PUT /image_vectors
{
// settings 部分用于配置索引的各种参数,影响索引的性能、可用性和存储等方面。
"settings": {
// index 是索引设置的主要配置项。
"index": {
// number_of_shards 指定索引的主分片数量,这里设置为 3。
// 分片是 Elasticsearch 中对索引进行水平拆分的机制,多个分片可以分布在不同的节点上,
// 从而提高索引的并发处理能力和数据的存储容量。
"number_of_shards": 3,
// number_of_replicas 指定每个主分片的副本数量,这里设置为 1。
// 副本是主分片的复制,用于提高数据的可用性和容错能力。当主分片所在节点出现故障时,
// 副本可以接替主分片继续提供服务。
"number_of_replicas": 1,
// knn 设置为 true 表示启用该索引的 k - 近邻(KNN)搜索功能。
// 因为后续我们要使用向量进行近似最近邻搜索,所以需要开启此功能。
"knn": true
}
},
// mappings 部分用于定义索引中文档的结构和字段类型。
"mappings": {
// properties 用于描述索引中各个字段的属性。
"properties": {
// 定义名为 image_vector 的字段,用于存储图像的向量表示。
"image_vector": {
// 指定该字段的类型为 dense_vector,即密集向量类型,适合存储连续的数值向量。
"type": "dense_vector",
// dims 指定向量的维度,这里设置为 512,意味着该向量有 512 个元素。
// 通常图像经过特征提取模型处理后会得到固定维度的向量表示,这里的 512 维就是这种表示的维度。
"dims": 512,
// index 设置为 true 表示对该向量字段进行索引,以便后续进行快速的向量搜索。
"index": true,
// similarity 指定计算向量相似度时使用的方法,这里选择余弦相似度。
// 余弦相似度常用于衡量向量之间的方向相似性,在语义搜索等场景中较为常用。
"similarity": "cosine",
// index_options 用于配置向量索引的具体参数。
"index_options": {
// type 指定使用的近似最近邻(ANN)算法,这里选择 hnsw(Hierarchical Navigable Small World)。
// HNSW 是一种高效的 ANN 算法,能够在高维向量空间中快速找到近似的最近邻。
"type": "hnsw",
// m 是 HNSW 算法的一个重要参数,它表示每个节点在图中的最大连接数。
// 这里设置为 32,较大的值可以提高搜索的准确性,但会增加索引的构建时间和存储空间。
"m": 32,
// ef_construction 也是 HNSW 算法的参数,它控制在构建索引时每个节点探索的邻居数量。
// 这里设置为 200,较大的值可以提高索引的质量,但同样会增加构建时间。
"ef_construction": 200
}
}
}
}
}
2.2 查询DSL模板
- DSL 即 Domain - Specific Language(领域特定语言)
- 是为特定领域或特定问题而设计的计算机语言,与通用编程语言(如 Python、Java 等)相对。
- 内部 DSL:基于通用编程语言构建,利用通用编程语言的语法和结构来实现特定领域的功能。例如,在 Python 中使用装饰器和函数调用的方式实现一个简单的测试框架,这个测试框架就是一个内部 DSL。
- 外部 DSL:具有自己独立的语法和解析器,不依赖于通用编程语言。例如,SQL、正则表达式等都是典型的外部 DSL。
- 应用场景:数据库操作、配置管理、业务规则引擎、图形化设计。
- 示例:SQL(数据库查询语言)、正则表达式(文本模式匹配语言)、配置文件(如 Nginx 配置)等
// 向 Elasticsearch 发送 GET 请求,对名为 image_vectors 的索引进行搜索。
GET /image_vectors/_search
{
// knn 部分表示使用 k - 近邻(KNN)搜索功能,用于在向量空间中查找与查询向量最相似的文档。
"knn": {
// field 指定要进行搜索的向量字段,这里是 image_vector,也就是之前索引中存储图像向量的字段。
"field": "image_vector",
// query_vector 是查询向量,由一系列数值组成,这里用 [0.12, 0.34, ...] 表示。
// Elasticsearch 会在索引中查找与该查询向量最相似的文档。
"query_vector": [0.12, 0.34, ...],
// k 指定要返回的最相似文档的数量,这里设置为 10,即返回与查询向量最相似的 10 个文档。
"k": 10,
// num_candidates 是一个优化参数,它指定在搜索过程中首先考虑的候选文档数量。
// Elasticsearch 会从这些候选文档中筛选出最终的 k 个最相似文档。这里设置为 100,
// 较大的值可以提高搜索的准确性,但会增加搜索的时间和资源消耗。
"num_candidates": 100,
// filter 用于对搜索结果进行过滤,只返回满足特定条件的文档。
"filter": {
// term 是一种过滤类型,用于精确匹配字段的值。
// 这里表示只返回 category 字段值为 "animal" 的文档。
"term": { "category": "animal" }
}
},
// fields 指定在搜索结果中要返回的字段,这里指定返回 title 和 category 字段。
// 这样搜索结果中只会包含这两个字段的信息,而不是整个文档的内容。
"fields": ["title", "category"]
}
3. 算法参数调优
3.1 HNSW参数矩阵
参数 | 默认值 | 推荐范围 | 影响维度 | 调优建议 |
---|---|---|---|---|
m | 16 | 24-48 | 图连接数 | 越大精度↑内存↑ |
ef_construction | 100 | 200-400 | 索引质量 | 越大精度↑索引时间↑ |
ef_search | 100 | 200-800 | 搜索质量 | 越大精度↑延迟↑ |
max_connections | 100 | 50-200 | 节点最大连接 | 平衡性能与内存 |
3.2 IVF优化策略
{
// index_options 用于配置 Elasticsearch 中向量索引的具体参数,这里配置的是使用倒排文件(IVF,Inverted File)算法相关的索引选项。
"index_options": {
// type 指定使用的近似最近邻(ANN)算法类型,这里设置为 "ivf",即使用倒排文件算法。
// 倒排文件算法是一种常用的 ANN 算法,它通过将向量空间划分为多个聚类中心(质心),
// 并建立倒排索引来提高向量搜索的效率。
"type": "ivf",
// nlist 表示倒排文件中聚类中心(质心)的数量,这里设置为 4096。
// 这个值决定了向量空间被划分的粒度,较大的 nlist 值会使每个聚类包含更少的向量,
// 可以提高搜索的精度,但会增加索引构建和搜索的时间;较小的 nlist 值则相反。
"nlist": 4096,
// nprobes 是在搜索时要检查的聚类中心的数量,这里设置为 20。
// 当进行向量搜索时,Elasticsearch 会从 nprobes 个聚类中心对应的向量集合中查找近似最近邻。
// 增加 nprobes 的值可以提高搜索的准确性,但会增加搜索的时间;减少 nprobes 的值则会加快搜索速度,但可能会降低搜索的准确性。
"nprobes": 20,
// code_size 表示每个向量的量化码本的大小,这里设置为 8。
// 在使用 IVF 算法时,通常会结合乘积量化(PQ,Product Quantization)来进一步压缩向量存储。
// code_size 决定了每个子向量的量化位数,较大的 code_size 可以提高量化的精度,但会增加存储空间;
// 较小的 code_size 则可以减少存储空间,但会降低量化的精度。
"code_size": 8,
// code_version 表示量化码本的版本号,这里设置为 "1.0"。
// 这个版本号用于标识量化码本的特定版本,在更新或维护索引时,
// 可以通过版本号来确保使用的是正确的量化码本,避免因码本不一致导致的搜索结果不准确。
"code_version": "1.0"
}
}
- 参数关系式:
召回率 ≈ min(nprobes/nlist, 1) * 100%
4. 企业级应用案例
4.1 电商图像搜索
// 批量插入数据部分
// 向 Elasticsearch 发送 PUT 请求,使用 _bulk API 对名为 product_vectors 的索引进行批量操作。
// _bulk API 允许在一个请求中执行多个索引、更新或删除操作,从而提高数据写入的效率。
PUT /product_vectors/_bulk
// 这是一个元数据行,指示接下来要执行的操作是索引操作(即插入文档)。
// _id 指定了要插入文档的唯一标识符,这里设置为 "1"。
{
"index": {
"_id": "1"
}
}
// 这是要插入的文档内容。
// image_vector 是一个向量字段,存储了图像的向量表示,这里用 [0.23,0.56,...] 表示具体的向量值。
// product_id 是产品的唯一标识符,这里为 "P1001"。
// category 表示产品的类别,这里是 "electronics",表示电子产品。
{
"image_vector": [0.23,0.56,...],
"product_id": "P1001",
"category": "electronics"
}
// 同样,这是另一个元数据行,指示要执行索引操作,文档的唯一标识符为 "2"。
{ "index": { "_id": "2" }}
// 要插入的第二个文档内容。
// image_vector 存储了另一个图像的向量表示。
// product_id 为 "P1002"。
// category 为 "clothing",表示服装类产品。
{
"image_vector": [0.78,0.12,...],
"product_id": "P1002",
"category": "clothing"
}
// 搜索数据部分
// 向 Elasticsearch 发送 GET 请求,对名为 product_vectors 的索引进行搜索。
GET /product_vectors/_search
{
// knn 部分表示使用 k - 近邻(KNN)搜索功能,用于在向量空间中查找与查询向量最相似的文档。
"knn": {
// field 指定要进行搜索的向量字段,这里是 image_vector,即之前插入文档中存储图像向量的字段。
"field": "image_vector",
// query_vector 是查询向量,由一系列数值组成,这里用 [0.65,0.32,...] 表示。
// Elasticsearch 会在索引中查找与该查询向量最相似的文档。
"query_vector": [0.65,0.32,...],
// k 指定要返回的最相似文档的数量,这里设置为 50,即返回与查询向量最相似的 50 个文档。
"k": 50,
// num_candidates 是一个优化参数,它指定在搜索过程中首先考虑的候选文档数量。
// Elasticsearch 会从这些候选文档中筛选出最终的 k 个最相似文档。这里设置为 200,
// 较大的值可以提高搜索的准确性,但会增加搜索的时间和资源消耗。
"num_candidates": 200,
// filter 用于对搜索结果进行过滤,只返回满足特定条件的文档。
"filter": {
// term 是一种过滤类型,用于精确匹配字段的值。
// 这里表示只返回 category 字段值为 "clothing" 的文档,即只搜索服装类产品。
"term": { "category": "clothing" }
}
}
}
- 性能指标:
- 索引规模:1亿向量
- 查询延迟:
<50ms P99
- 准确率:Recall@10=96.5%
- 吞吐量:1200 QPS
4.2 生物特征识别
// 向 Elasticsearch 发送 PUT 请求,用于在 KNN(k - 近邻)插件中注册一个名为 face_model 的模型。
PUT _plugins/_knn/models/face_model
{
// description 字段用于对模型进行简要描述,这里说明该模型是用于人脸识别的。
// 描述信息可以帮助用户和开发者快速了解模型的用途。
"description": "Face recognition model",
// model_id 是该模型的唯一标识符,这里设置为 "face_v1"。
// 在后续对该模型进行操作(如查询、使用等)时,会依据这个唯一的 ID 来定位模型。
"model_id": "face_v1",
// model_type 指定了模型所使用的近似最近邻(ANN)算法类型,这里选择 "hnsw",即 Hierarchical Navigable Small World。
// HNSW 是一种高效的 ANN 算法,能够在高维向量空间中快速找到近似的最近邻。
"model_type": "hnsw",
// dimension 表示模型所处理的向量的维度,这里设置为 1024。
// 通常在人脸识别等场景中,经过特征提取后的人脸向量会有固定的维度,这里的 1024 维就是该人脸向量的维度。
"dimension": 1024,
// training_data 部分用于指定训练模型所使用的数据来源。
"training_data": {
// index 指定了存储训练数据的 Elasticsearch 索引名称,这里是 "face_vectors"。
// 该索引中应该包含用于训练模型的向量数据。
"index": "face_vectors",
// field 指定了在索引中存储向量数据的字段名,这里是 "embedding"。
// 也就是说,模型会从 "face_vectors" 索引的 "embedding" 字段中获取训练所需的向量数据。
"field": "embedding"
},
// training_parameters 部分用于配置模型训练时的参数,这些参数会影响模型的性能和效果。
"training_parameters": {
// m 是 HNSW 算法的一个重要参数,它表示每个节点在图中的最大连接数。
// 这里设置为 48,较大的值可以提高搜索的准确性,但会增加索引的构建时间和存储空间。
"m": 48,
// ef_construction 也是 HNSW 算法的参数,它控制在构建索引时每个节点探索的邻居数量。
// 这里设置为 500,较大的值可以提高索引的质量,但同样会增加构建时间。
"ef_construction": 500
}
}
- 安全配置:
- 加密存储:AES-256向量加密
- 访问控制:
RBAC+字段级权限
- 审计日志:全量操作记录
5. 算法选型决策树
6. 未来演进方向
6.1 硬件加速方案
技术方向 | 实现方式 | 预期收益 | 商用化进度 |
---|---|---|---|
GPU加速 | CUDA内核优化 | 5-10倍速度提升 | 部分云服务支持 |
FPGA加速 | 定制化向量处理单元 | 3-5倍能效比 | 实验室阶段 |
存算一体 | 近内存计算架构 | 10倍吞吐提升 | 预研阶段 |
FPGA
- 是一种可编程的集成电路芯片,通过硬件描述语言(如 Verilog/VHDL)或图形化工具定义其逻辑功能。
- 示例应用
- FPGA与GPU/CPU的对比
维度 | FPGA | GPU | CPU |
---|---|---|---|
计算模式 | 硬件定制化并行(ASIC级性能) | 通用并行(CUDA/OpenCL) | 串行/多核并行 |
延迟 | 低(微秒级) | 中(毫秒级) | 高(毫秒级) |
功耗 | 低(10-100W) | 高(200-400W) | 中(50-150W) |
灵活性 | 需硬件开发(Verilog/VHDL) | 软件编程(Python/C++) | 通用指令集(C++/Java) |
适用场景 | 专用加速(如KNN、加密、视频处理) | 通用AI训练/推理(如ResNet) | 通用逻辑控制 |
6.2 算法演进趋势
-
- 混合索引技术:HNSW+PQ组合优化
-
- 动态图更新:
实时增量索引构建
- 动态图更新:
-
- 自适应参数:
AI驱动的参数调优
- 自适应参数:
-
- 多模态融合:
跨文本/图像联合搜索
- 多模态融合:
- 附录:向量搜索工具箱
工具类别 | 推荐方案 | 核心功能 |
---|---|---|
性能测试 | ann-benchmarks | 算法基准测试框架 |
可视化分析 | TensorBoard Projector | 高维向量可视化 |
模型训练 | FAISS | 向量索引训练 |
质量评估 | GIST数据集 | 召回率评估标准 |
ANN-Benchmarks
近似最近邻搜索(Approximate Nearest Neighbor, ANN)算法的基准测试工具。
- 评估不同 ANN 算法(如 HNSW、IVF、LSH 等)在速度、精度、内存占用等方面的性能。
- 支持自定义数据集和查询参数,提供标准化的对比结果。
TensorBoard Projector
TensorFlow 生态中的可视化工具,用于高维数据降维和交互式探索。
- 通过 PCA、t-SNE 等降维技术将高维向量投影到 2D/3D 空间。
- 支持标签、颜色分组和交互式缩放,帮助分析数据分布和聚类效果。
FAISS
Facebook 开源的高效向量相似性搜索库,支持十亿级向量的 ANN 搜索和聚类。
- 倒排索引(IVF):将向量聚类为子空间,搜索时仅遍历最相关的子空间。
- 乘积量化(PQ):压缩向量存储(如将 128 维向量压缩为 8 字节),加速距离计算。
GIST 数据集!!!
用于机器学习推荐和评级的公共数据集,包含用户行为、物品特征等信息。
- 训练推荐系统模型(如协同过滤、双塔模型)。
- 测试向量搜索算法在真实场景中的效果(如用户兴趣匹配)。
四者的协同应用场景
推荐系统优化:
- 使用 GIST 数据集训练用户和物品的嵌入向量。
- 用 FAISS 构建向量索引,实现快速 KNN 搜索。
- 通过 TensorBoard Projector 可视化嵌入向量,分析推荐结果的合理性。
- 用 ANN-Benchmarks 对比 FAISS 与其他算法(如 HNSW)的性能,选择最优方案。
图像检索:
- 将
图像特征(如 ResNet 输出)压缩后存入 FAISS 索引
。 - 通过 TensorBoard Projector 观察不同类别的图像在低维空间中的分布。
- 用 ANN-Benchmarks 评估不同压缩策略(如 PQ 参数)对检索速度和精度的影响。
- 将
示例工作流程
实施建议:
生产环境推荐 HNSW+IVF 复合索引
- 定期执行Recall / Latency平衡测试
- 建立向量数据版本管理机制
注意8.x版本后的API变更