IVF 索引与训练
IndexIVFFlat 是倒排文件索引:先用代表性样本训练出 nlist 个聚类中心,再把向量分配到最近的簇,查询时只扫描 nprobe 个簇,从而把比较次数降到可接受范围。因此它必须「先训练后添加」,且训练样本要有代表性;数据分布发生明显变化后,簇中心会失配,需要重新训练或重建索引。
基本信息
| 前置步骤 | 先 train 学习簇中心,再 add 数据 |
|---|---|
| 训练样本 | 数量与 nlist 同阶或更多时聚类更稳定 |
| 查询参数 | nprobe 控制每次查询扫描的簇数 |
| 存储特征 | IndexIVFFlat 保留原始向量,不损失精度 |
典型使用场景
- 大规模离线检索:向量上千万时用倒排减少比较次数
- 内存与速度折中:相比精确检索更快,相比图索引更省内存
- 与量化组合:换成 IVF_SQ8 等变体压缩存储,适合内存紧张环境
- 批量召回实验:作为基线对比 HNSW 的召回与耗时
- 增量可接受场景:新数据追加方便,定期重建即可
训练与查询
训练与查询
import faiss, numpy as np
d = 384; nlist = 1024 # 簇数量
quantizer = faiss.IndexFlatL2(d) # 用精确索引当量化器
index = faiss.IndexIVFFlat(quantizer, d, nlist, faiss.METRIC_L2)
index.train(np.random.rand(200000, d).astype("float32")) # 先训练簇中心
index.add(np.random.rand(1000000, d).astype("float32")) # 再写入数据
index.nprobe = 32 # 查询扫描的簇数
D, I = index.search(np.random.rand(1, d).astype("float32"), 10)
参数与取值方向
| 参数 | 作用 | 取值方向 |
|---|---|---|
| nlist | 簇的数量 | 从 4 倍数据量平方根附近起步再调 |
| nprobe | 查询扫描的簇数 | 从 nlist 的十分之一附近起步 |
| 训练样本量 | 决定簇中心质量 | 至少与 nlist 同阶 |
| 量化后缀 | 如 IVF_SQ8 压缩存储 | 内存紧张时考虑,需评测精度 |
训练样本量与 nlist 同阶或更多时聚类更稳定;样本过少会让部分簇形同虚设,查询扫到空簇等于白费一次比较。
删除与更新不方便是倒排结构的老问题:频繁变更的语料更适合服务化向量库,把 IVF 用在相对稳定的批量数据上收益更明显。
训练和写入要一起纳入流水线:训练的簇中心与写入的数据必须来自同一批预处理脚本,若分词或归一化方式变了而索引没重建,召回会静默下滑。