HNSW 索引¶
层次化可导航小世界(Hierarchical Navigable Small World,HNSW)是 GoVector 中的默认索引类型,提供高效的近似最近邻(ANN)搜索。本文档解释 HNSW 的工作原理以及如何针对您的用例进行优化。
📋 HNSW 概述¶
HNSW 是一种最先进的近似最近邻搜索算法,它:
- 提供高召回率(对于调优的参数,接近 100%)
- 提供快速搜索性能(O(log N) 复杂度)
- 很好地扩展到高维向量(高达数千维)
- 支持动态插入新向量
🔧 HNSW 参数¶
核心参数¶
| 参数 | 描述 | 默认值 | 范围 | 影响 |
|---|---|---|---|---|
M |
每个节点的连接数 | 16 | 4-64 | 值越高,准确性和内存使用越高 |
EfConstruction |
索引构建过程中动态候选列表的大小 | 200 | 10-∞ | 值越高,索引质量越好,但构建时间越长 |
EfSearch |
搜索过程中动态候选列表的大小 | 10 | 10-∞ | 值越高,召回率越好,但搜索时间越长 |
🚀 创建 HNSW 索引¶
嵌入式模式¶
import (
"github.com/yourusername/govector/core"
)
// 创建带有 HNSW 索引的集合
collection, err := core.NewCollection(core.CollectionConfig{
Name: "my-collection",
VectorLen: 768,
Metric: core.Cosine,
IndexType: core.HNSW, // 使用 HNSW 索引
M: 16, // 每个节点的连接数
EfConstruction: 200, // 构建参数
EfSearch: 10, // 搜索参数
})
if err != nil {
log.Fatalf("创建集合失败: %v", err)
}
微服务模式¶
curl -X POST http://localhost:6333/collections \
-H "Content-Type: application/json" \
-d '{
"name": "my-collection",
"vectors": {
"size": 768,
"distance": "Cosine"
},
"hnsw_config": {
"m": 16,
"ef_construction": 200,
"ef": 10
}
}'
📊 HNSW 工作原理¶
HNSW 创建一个多层图结构,其中:
- 每一层都是一个可导航的小世界图
- 较高层作为较低层的粗略引导
- 搜索从顶层开始,向下导航以找到最近邻
- 插入遵循类似的路径,在每一层建立连接
搜索过程¶
flowchart TD
A[从顶层开始] --> B[在当前层找到最近邻]
B --> C{当前层是底层?}
C -->|否| D[移动到下一层]
D --> B
C -->|是| E[返回最近邻]
插入过程¶
flowchart TD
A[从顶层开始] --> B[在当前层找到最近邻]
B --> C{当前层是底层?}
C -->|否| D[移动到下一层]
D --> B
C -->|是| E[插入节点并建立连接]
E --> F[可能将节点添加到更高层]
💡 优化技巧¶
对于大型数据集¶
- 增加
M到 24-32 以获得更高的召回率 - 增加
EfConstruction到 400-1000 以获得更好的索引质量 - 使用
EfSearch在 50-100 之间以获得高召回率应用 - 启 SQ8 量化 以减少内存使用
对于快速搜索¶
- 减少
M到 8-12 以加快索引速度并降低内存使用 - 设置
EfSearch为 10-20 以加快搜索速度(以召回率为代价) - 尽可能使用较小的向量(例如,使用 384 维而不是 768 维)
对于内存约束¶
- 启 SQ8 量化 以减少约 75% 的内存
- 使用较小的
M值(8-12) - 考虑 Flat 索引 对于非常小的数据集(< 10,000 点)
📈 性能基准¶
搜索性能¶
| 数据集大小 | M | EfSearch | 召回率 | QPS |
|---|---|---|---|---|
| 100K 点 | 16 | 10 | ~0.9 | 10,000+ |
| 100K 点 | 16 | 50 | ~0.95 | 5,000+ |
| 100K 点 | 16 | 100 | ~0.99 | 2,000+ |
| 1M 点 | 16 | 10 | ~0.85 | 5,000+ |
| 1M 点 | 16 | 50 | ~0.9 | 2,000+ |
| 1M 点 | 16 | 100 | ~0.95 | 1,000+ |
内存使用¶
| 数据集大小 | 向量维度 | M | 内存(无量化) | 内存(带 SQ8) |
|---|---|---|---|---|
| 100K 点 | 768 | 16 | ~1GB | ~250MB |
| 1M 点 | 768 | 16 | ~10GB | ~2.5GB |
| 10M 点 | 768 | 16 | ~100GB | ~25GB |
🚩 常见问题¶
索引构建缓慢¶
- 原因:
EfConstruction值过高或数据集过大 - 解决方案:为数据集大小使用适当的
EfConstruction,考虑批量插入
召回率低¶
- 原因:
EfSearch或M值过低 - 解决方案:增加
EfSearch以提高搜索时的召回率,增加M以提高索引质量
内存使用高¶
- 原因:
M值过大或未启量化 - 解决方案:启 SQ8 量化,减少
M值