4、选型第二关:索引算法与召回率:HNSW、IVF、PQ、DiskANN的原理对比,如何平衡速度与精度。

索引算法,说白了就是向量数据库的「内功心法」。你选再好的硬件,配再牛的集群,索引没选对,召回率就是上不去。我见过不少团队,一上来就上 HNSW,结果内存爆了;也有人图省事用 IVF,结果召回率惨不忍睹。嗯,这一关咱们得好好聊聊。

4.1 四大索引算法的核心差异

先看一张总览图,把四个算法的定位搞清楚。

四大索引算法核心对比 HNSW 分层导航小世界 速度:★★★★★ 精度:★★★★★ 内存:★★★★★(高) 适用:纯内存场景 IVF 倒排文件聚类 速度:★★★☆☆ 精度:★★★☆☆ 内存:★★☆☆☆(低) 适用:海量数据 PQ 乘积量化压缩 速度:★★★★☆ 精度:★★☆☆☆ 内存:★☆☆☆☆(极低) 适用:内存受限 DiskANN 磁盘感知图 速度:★★★☆☆ 精度:★★★★☆ 内存:★★☆☆☆(低) 适用:超大规模 选型核心逻辑 1. 数据量 < 100万 → HNSW(纯内存,速度精度双优) 2. 数据量 100万~1000万 → IVF+PQ(平衡内存与精度) 3. 数据量 > 1000万 → DiskANN(磁盘换内存,精度不妥协) 4. 内存受限 < 1GB → PQ(极致压缩,但召回率会掉) 5. 实时插入频繁 → HNSW(动态图结构,插入友好) 6. 批量构建为主 → IVF(聚类一次,查询高效)

4.2 HNSW:速度与精度的天花板

HNSW 是我个人最常用的算法。它基于「分层小世界图」的思想,说白了就是给数据建了多层高速公路。顶层是稀疏的快速通道,底层是密集的精细搜索。

我记得有一次做电商相似商品检索,数据量 500 万,128 维向量。用 HNSW,QPS 能到 3000,召回率 99% 以上。但代价是什么?内存。500 万条数据吃了将近 8GB 内存。

核心参数:

  • M:每个节点的最大连接数。M 越大,图越密,召回率越高,但内存和建图时间也越大。我一般设 16~32。
  • efConstruction:建图时的动态候选集大小。efConstruction 越大,图质量越好,但建图越慢。我习惯设 200~400。
  • efSearch:查询时的动态候选集大小。efSearch 越大,召回率越高,但延迟也越高。线上我通常设 64~128。

我的经验:HNSW 的 efSearch 和召回率不是线性关系。efSearch 从 32 提到 64,召回率能涨 5 个点;但从 128 提到 256,可能只涨 0.5 个点。所以别盲目堆参数,够用就行。

4.3 IVF:海量数据的性价比之选

IVF 的原理很简单:先对数据做 K-Means 聚类,查询时只搜索最近的几个簇。你想想看,这就像去图书馆找书,先确定书架号,再在书架上找,而不是一本本翻。

IVF 最大的优点是内存友好。同样是 500 万条数据,IVF 可能只占 2GB 内存,比 HNSW 省了 75%。但代价是什么?召回率。我做过测试,同样的数据,IVF 的召回率比 HNSW 低 3~5 个百分点。

避坑指南:我曾经在一个项目中用 IVF,nprobe 设了 10,结果召回率只有 85%。后来发现是聚类数 nlist 设得太小了。nlist 一般设为 sqrt(N) 左右,比如 500 万数据,nlist 设 2000~3000 比较合理。

4.4 PQ:内存不够时的救命稻草

PQ 的核心思想是「压缩」。它把高维向量拆成多个子空间,每个子空间独立量化。说白了,就是把一个 128 维的 float 向量,压缩成几十个字节。

我见过一个极端案例:某团队用 256 维向量,数据量 1 亿条,内存只有 32GB。用 HNSW 直接爆内存,用 IVF 也勉强。最后用 PQ,把每个向量压缩到 32 字节,内存占用降到 3GB,虽然召回率只有 92%,但至少能跑起来。

PQ 的关键参数:

  • M:子空间数量。M 越大,压缩比越高,但精度损失也越大。我一般设 8~16。
  • nbits:每个子空间的量化位数。nbits=8 时,每个子空间有 256 个码本。nbits 越小,压缩越狠,但精度越差。

我的建议:PQ 很少单独用,通常和 IVF 搭配,即 IVF+PQ。先用 IVF 缩小搜索范围,再用 PQ 做距离计算。这样既能控制内存,又能保证一定的召回率。

4.5 DiskANN:超大规模数据的终极方案

DiskANN 是微软出的算法,专门解决「数据太大,内存装不下」的问题。它的核心思路是把图结构放在 SSD 上,查询时只加载必要的节点到内存。

我记得有个客户,数据量 10 亿,128 维向量,内存只有 64GB。用 HNSW 根本不可能,用 IVF+PQ 召回率又不够。最后上了 DiskANN,召回率 98%,QPS 能到 500,延迟 20ms 左右。

避坑指南:DiskANN 对 SSD 的 IOPS 要求很高。我曾经用普通 SATA SSD 跑 DiskANN,延迟直接飙到 100ms+。后来换了 NVMe SSD,延迟降到 15ms。所以,用 DiskANN 之前,先看看你的磁盘性能够不够。

4.6 速度与精度的平衡策略

选索引算法,说白了就是在「速度、精度、内存」三个维度上做取舍。没有完美的算法,只有最适合你场景的算法。

场景 推荐算法 速度 精度 内存
小数据量(<100万) HNSW 极高 极高 高
中等数据量(100万~1000万) IVF+PQ 高 中 低
大数据量(>1000万) DiskANN 中 高 低
内存受限(<1GB) PQ 中 低 极低
实时插入频繁 HNSW 极高 极高 高

我的平衡公式:

  • 如果内存够 → 无脑 HNSW,参数调优后召回率 99%+
  • 如果内存不够但精度要求高 → DiskANN,用磁盘换内存
  • 如果内存不够且精度要求不高 → IVF+PQ,性价比最高
  • 如果内存极度受限 → 纯 PQ,但要做好召回率掉到 85% 以下的准备

4.7 实战调参建议

最后,分享几个我常用的调参套路:

  1. 先跑小数据:用 10 万条数据做基准测试,快速找到参数范围。
  2. 监控召回率:用 recall@10 作为核心指标,别只看 QPS。
  3. 逐步放大:参数确定后,用全量数据验证,注意内存和建图时间。
  4. 线上 A/B 测试:别一次性全量切换,先灰度 10% 的流量看看效果。

我的经验:调参时,先固定 efSearch 和 nprobe,调 M 和 nlist。M 和 nlist 决定了图的结构,efSearch 和 nprobe 决定了搜索的深度。结构对了,深度调起来才有意义。