IVF 倒排索引是什么
IVF 先用聚类把向量空间划成若干簇,查询时只扫描距离最近的少数几簇,用少量召回损失换取明显的延迟下降,适合百万级以上的数据集。它的两个核心参数是簇数量与查询扫描的簇数,两者与数据量、召回目标一起决定实际表现,无法直接照搬示例值。
基本信息
| nlist | 聚类数,常见做法取数据量的平方根量级 |
|---|---|
| nprobe | 查询扫描的聚类数,常用范围在 1 到 128 之间 |
| 训练 | 必须先训练再添加向量,训练集规模需大于聚类数 |
| 特性 | 近似检索,召回随 nprobe 上升而提高 |
FAISS IVF 最小示例
FAISS IVF 最小示例
import faiss, numpy as np
d = 768; nlist = 256
quantizer = faiss.IndexFlatL2(d)
index = faiss.IndexIVFFlat(quantizer, d, nlist)
train_xb = np.random.rand(100000, d).astype("float32")
index.train(train_xb)
index.add(np.random.rand(500000, d).astype("float32"))
index.nprobe = 16
D, I = index.search(np.random.rand(1, d).astype("float32"), 10)使用要点
- 先训练后添加:顺序颠倒会直接报错,训练样本质量决定聚类质心位置
- 训练样本要覆盖真实分布,只用少量样本训练会让质心偏离
- nprobe 从小到大扫一遍,画出召回与延迟曲线再定值
- 数据增量很大时考虑重建索引,簇的分布会随数据漂移
- 与量化结合可显著压缩内存,但要接受额外的精度损失
参数与影响
| 参数 | 调大 | 调小 |
|---|---|---|
| nlist | 簇更细、召回更依赖 nprobe | 簇更粗、单簇扫描量上升 |
| nprobe | 召回提高、延迟上升 | 更快,可能漏掉目标簇 |
| 训练样本量 | 质心更准 | 质心偏移,召回下降 |
常见问题
- 召回突然下降且无报错:多因 nprobe 过小,目标向量所在的簇没被扫描
- 查询变慢但召回没提升:nprobe 已经过大,继续调收益递减
- 簇数量远超数据量:大量空簇被训练,索引质量反而下降
- 训练集与线上数据分布不一致:离线指标好、线上效果差
未调用训练就添加向量会直接报错;训练样本过少时聚类质心偏差大,召回会显著变差且不容易从指标上看出原因。
上线前验证
- 用精确检索作为基线,量化近似索引带来的召回损失
- 在不同 nprobe 取值下画召回与延迟曲线,选拐点处的配置
- 用真实查询而非随机向量测试,随机向量的分布与业务数据差别很大
- 记录索引构建耗时与内存占用,作为容量规划的输入