Skip to content
🔗 分享本题
查看我的学习进度 →

Flat、HNSW、IVF、IVF-PQ 与 LSH 向量索引的核心机制和选型权衡

🧠 记忆锚点:Flat 做真值,HNSW 用图换低延迟,IVF 先分桶,PQ 用精度换内存;用同一数据集压测选型。

💡 完整答案

主流索引类型对比:

索引类型全称原理速度精度内存适用场景
HNSWHierarchical Navigable Small World多层图结构,贪心搜索⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐追求速度,内存充足
IVFInverted File Index先聚类,再在簇内搜索⭐⭐⭐⭐⭐⭐⭐数据量大,可接受精度损失
IVF-PQIVF + Product QuantizationIVF + 向量压缩⭐⭐⭐⭐⭐⭐⭐内存受限,大数据量
LSHLocality Sensitive Hashing局部敏感哈希⭐⭐⭐⭐⭐⭐超大规模,近似即可
Flat暴力搜索计算所有距离⭐⭐⭐⭐⭐<1 万条数据

一、HNSW(层次导航小世界)

原理:

HNSW = 多层图结构 + 贪心搜索

1. 构建多层图:
   - 顶层:节点少,长距离跳跃
   - 底层:节点多,精细搜索
   - 每层都是一个小世界网络

2. 搜索过程:
   - 从顶层入口开始
   - 贪心搜索:找最近的邻居
   - 找到局部最优后,下降到下一层
   - 重复直到最底层

图示:

Layer 2 (顶层):  A ───── B

Layer 1 (中层):  C ───── D ───── E

Layer 0 (底层):  F ───── G ───── H ───── I

优点:

  • ✅ 在合适参数和数据分布下通常有很好的低延迟表现
  • ✅ 精度最高(接近暴力搜索)
  • ✅ 支持实时插入

缺点:

  • ❌ 内存占用高(存储图结构)
  • ❌ 构建时间长

性能数据:

  • 100 万条数据,检索延迟:< 10ms
  • 内存占用:约 1-2GB(1536 维)
  • 召回率(Recall@10):> 95%

适用场景:

  • 数据量 < 1000 万
  • 内存充足
  • 追求低延迟

代码示例(Milvus):

python
index_params = {
    "metric_type": "IP",  # 内积相似度
    "index_type": "HNSW",
    "params": {
        "M": 16,           # 每个节点的最大连接数
        "efConstruction": 200  # 构建时的搜索范围
    }
}
collection.create_index(field_name="embedding", index_params=index_params)

二、IVF(倒排文件索引)

原理:

IVF = 聚类 + 分桶搜索

1. 训练阶段:
   - 用 K-Means 把向量聚成 N 个簇(如 1024 个)
   - 每个簇有一个质心(centroid)

2. 索引阶段:
   - 每个向量分配到最近的簇
   - 建立 簇 ID → 向量列表 的倒排索引

3. 搜索阶段:
   - 计算查询向量与各簇质心的距离
   - 选最近的 k 个簇(如 k=10)
   - 只在这 k 个簇内暴力搜索

图示:

        查询向量 Q

    ┌───────┼───────┐
    ↓       ↓       ↓
  簇 1     簇 2     簇 3  ← 计算与质心距离
    │       │       │
    └───────┼───────┘

        选最近的 3 个簇

    只在选中簇内暴力搜索

优点:

  • ✅ 内存占用适中
  • ✅ 适合大数据量
  • ✅ 构建速度快

缺点:

  • ❌ 精度有损失(近似搜索)
  • ❌ 需要调参(簇数量)

性能数据:

  • 100 万条数据,检索延迟:~50-100ms
  • 内存占用:约 500MB-1GB
  • 召回率(Recall@10):85-90%

适用场景:

  • 数据量 100 万 -1 亿
  • 可接受精度损失
  • 离线批量构建

代码示例(FAISS):

python
import faiss

# 创建 IVF 索引
d = 1536  # 向量维度
quantizer = faiss.IndexFlatL2(d)  # 质心索引
index = faiss.IndexIVFFlat(quantizer, d, nlist=1024)  # 1024 个簇

# 训练
index.train(vectors)

# 添加
index.add(vectors)

# 搜索
index.nprobe = 10  # 搜索 10 个簇
D, I = index.search(query_vector, k=10)

三、IVF-PQ(乘积量化)

原理:

IVF-PQ = IVF 聚类 + 向量压缩

1. IVF 聚类(同上)

2. 乘积量化(PQ):
   - 把 1536 维向量切成 M 段(如 16 段)
   - 每段 96 维(1536/16)
   - 每段独立聚类(如 256 个质心)
   - 用质心 ID(1 字节)代替原始向量
   - 1536 维 float(6144 字节)→ 16 字节

3. 搜索:
   - 在压缩空间计算近似距离
   - 速度快,内存小

压缩效果:

原始向量:1536 维 × 4 字节 (float32) = 6144 字节
PQ 压缩后:16 段 × 1 字节 (uint8) = 16 字节
压缩率:6144 / 16 = 384 倍

优点:

  • ✅ 内存占用极低
  • ✅ 适合超大数据量
  • ✅ 检索速度快

缺点:

  • ❌ 精度损失较大
  • ❌ 需要调参(分段数)

性能数据:

  • 1000 万条数据,内存占用:约 1-2GB
  • 检索延迟:~20-50ms
  • 召回率(Recall@10):80-85%

适用场景:

  • 数据量 > 1000 万
  • 内存受限
  • 可接受精度损失

四、LSH(局部敏感哈希)

原理:

LSH = 哈希 + 桶内搜索

1. 核心思想:
   - 相似的向量哈希后落在同一个桶
   - 不相似的向量哈希后落在不同桶

2. 哈希函数:
   - h(v) = sign(w · v)  w 是随机向量
   - 多个哈希函数组成哈希表

3. 搜索:
   - 计算查询向量的哈希值
   - 找到对应桶
   - 只在这个桶内暴力搜索

优点:

  • ✅ 内存占用低
  • ✅ 适合超大规模
  • ✅ 理论保证

缺点:

  • ❌ 精度最低
  • ❌ 哈希函数设计复杂

适用场景:

  • 数据量 > 1 亿
  • 精度要求不高
  • 近似搜索即可

五、Flat(暴力搜索)

原理:

计算查询向量与所有向量的距离,排序取 top-k

优点:

  • ✅ 精度 100%
  • ✅ 无需构建索引
  • ✅ 实现简单

缺点:

  • ❌ 速度最慢(O(N))
  • ❌ 不适合大数据量

性能数据:

  • 1 万条数据,检索延迟:< 10ms
  • 100 万条数据,检索延迟:~5000ms

适用场景:

  • 数据量 < 1 万
  • 精度要求极高
  • 原型验证

📚 参考:Milvus:向量索引说明文档