Faiss将向量搜索从O(N)降至近O(log N),通过索引、量化与压缩实现加速;选错索引类型会导致构建失败或结果不准,小规模用IndexFlatL2,中大规模依数据量选IVF或HNSW。
为什么直接用 NumPy 算余弦相似度会变慢
当向量数量超过 10 万,用 sklearn.metrics.pairwise.cosine_similarity 或手写 np.dot + 归一化做全量比对,内存和耗时会陡增——不是算法错,是它默认不做索引、不压缩、不量化,每次搜索都扫全库。Faiss 的价值不在“存向量”,而在把 search() 从 O(N) 压到接近 O(log N),尤其适合 query 频繁、index 相对静态的场景。
初始化 Faiss index 时必须选对类型
选错 Index 类型会导致构建失败或结果不准。常见组合:
- 小规模(faiss.IndexFlatIP(内积,等价于余弦,前提是向量已单位归一化)
- 中大规模(10 万–1 千万)、接受少量误差 → 用
faiss.IndexIVFFlat,必须调用train(),且nlist设为sqrt(N)左右(如 100 万向量设 1000) - 超大规模+内存敏感 → 加
faiss.IndexIVFPQ,但注意m(子向量数)需整除向量维度,nbits默认 8,降低到 4 会明显掉准
漏掉 train() 直接 add() 会报 RuntimeError: Index not trained;用 IndexFlatIP 却传入未归一化的向量,结果就不是余弦相似度。
插入和查询前必须处理向量格式
Faiss 只接受 C-contiguous 的 np.float32 二维数组,shape 为 (n_vectors, dim)。常见翻车点:
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
- PyTorch 输出默认是
float64或 GPU tensor → 必须.cpu().numpy().astype(np.float32) - scikit-learn 的
fit_transform结果可能是 Fortran order → 加np.ascontiguousarray() - 单条 query 向量 shape 是
(dim,),要 reshape 成(1, dim)才能喂给index.search()
否则会静默出错或返回全零距离 —— Faiss 不报类型错,只默默返回垃圾值。
如何让 top-k 搜索结果真正对应原始 ID
Faiss 返回的是内部索引位置(0-based),不是你原始数据的 ID。别直接用返回的 I[0] 当作用户 ID 或文件名:
- 构建 index 前,用
faiss.IndexIDMap包一层:index = faiss.IndexIDMap(faiss.IndexFlatIP(dim)) -
add()时传入ids数组(np.int64),比如原始 ID 是字符串,得先映射成 int,查完再反查字典 - 如果 ID 是长整型(如 MongoDB ObjectId 转的 int64),确保没溢出;超过
2^63-1会截断
跳过 ID 映射看似省事,但线上服务一旦要回溯来源、打日志、拼详情页,就会卡在“这第 372 行向量到底是谁的”上——这个环节没法事后补。