FAISS IndexFlat 是什么
IndexFlatL2 与 IndexFlatIP 是 FAISS 的暴力精确索引:查询时逐一计算与库中每个向量的距离,结果就是真实最近邻,没有任何近似误差。它不需要训练、可以随时追加向量,实现也最简单。代价是查询耗时随数据量线性增长:十万级还能接受,百万级单次查询就要扫描全量向量。它的两个不可替代用处是——数据量不大时的直接方案,以及作为近似索引的召回基线。
基本信息
| 类型 | 暴力精确检索(brute force) |
|---|---|
| 变体 | IndexFlatL2(欧氏)、IndexFlatIP(内积) |
| 训练 | 不需要,可直接 add |
| 复杂度 | 查询耗时与向量条数线性相关 |
| 常用搭配 | faiss.normalize_L2 后配 IndexFlatIP 等价余弦 |
典型使用场景
- 召回基线:为 HNSW、IVF 等近似索引提供精确对照
- 小规模直接使用:数据量在十万级内,精确结果更有价值
- 离线去重:对全量向量做精确近邻查找,识别重复与近似重复
- 结果校验:抽查线上近似检索的结果,确认没有系统性遗漏
- 原型验证:先把链路跑通,再按数据增长替换索引类型
IndexFlatIP 找相似(内积)
IndexFlatIP 找相似(内积)
import faiss, numpy as np
xb = np.random.rand(100000, 384).astype('float32')
faiss.normalize_L2(xb) # 归一化后内积等价余弦
index = faiss.IndexFlatIP(384)
index.add(xb)
q = np.random.rand(1, 384).astype('float32')
faiss.normalize_L2(q)
D, I = index.search(q, 5) # D 为相似度,I 为向量下标
print(I[0], D[0])两种 Flat 索引对比
| 索引 | 度量 | 使用要点 |
|---|---|---|
| IndexFlatL2 | 欧氏距离 | 结果越小越相似,无需归一化 |
| IndexFlatIP | 内积 | 需自行归一化,否则模长主导排序 |
| IndexFlat(通用) | 由构造参数决定 | 选择度量后不要再混用 |
| 配 IndexIDMap | 同上 | 需要业务主键时包一层 |
使用与迁移要点
- 先确认度量:余弦用 IP 并归一化,欧氏才用 L2,别混着配
- 规模判断:十万级可直接用,百万级以上评估 IVF 或 HNSW
- 落盘习惯:write_index 保存并在启动时校验 ntotal
- 主键映射:需要业务主键时用 IndexIDMap 包装,避免自建下标映射
替换为近似索引之前,务必先记录 Flat 的 Recall@10 作为基线:没有这条基线,就无法判断新索引到底损失了多少召回。