Skip to content

Faiss 项目调研

调研日期:2026-09-17。本文基于官方仓库、Wiki、API 和论文,侧重技术选型与实现理解。尚未执行 Faiss 性能实验,容量估算和实验参数不代表实测结果。正式复现时应固定 release 或 commit,并记录编译选项。

1. 调研目标与初步判断

本次调研关注三个问题:Faiss 解决什么问题,主要索引如何取舍,以及怎样验证它是否适合实际业务与硬件。

Faiss 是由 Meta 主导开发的稠密向量相似度检索与聚类库,核心使用 C++,提供 Python/NumPy 接口,采用 MIT 许可证。它提供多种索引,允许在检索质量、速度、存储与构建成本之间取舍。官方仓库

本文的初步判断是:Faiss 适合作为向量检索算法基线、单机检索组件和底层性能研究对象。用于线上服务时,还需要围绕它设计数据管理、服务接口与运维机制。最终选型应由真实数据上的实验决定。

2. 在检索系统中的位置

以文档检索为例,可以将应用设计为以下流程:

离线:文档 → 切分 → embedding 模型 → 向量 → Faiss 索引
                     文档内容与业务 ID → 元数据存储

在线:查询 → 同一 embedding 模型 → Faiss top-k → ID 回查 → 重排 → 返回结果

这里的流程是应用架构建议。Faiss 接收向量并返回邻居 ID 与距离或分数;embedding 生成、原文存储和业务相关性判断需要其他组件承担。向量检索准确并不意味着 embedding 能正确表达业务语义,二者需要分别评估。官方简介

3. 距离度量与核心接口

检索目标 常见选择 注意事项
欧氏距离最近 IndexFlatL2 返回平方 L2 距离,越小越近
内积最大 IndexFlatIP 返回内积分数,越大越相似
余弦相似度最大 归一化后使用内积索引 库向量和查询向量都要归一化

对非零单位向量,平方 L2 距离等于 2 - 2 × 内积,因此精确检索排序等价。未经归一化时,内积会受到库向量模长影响,不能直接当作余弦相似度。距离定义

核心生命周期是 train → add → search:训练阶段学习聚类中心、量化码本等索引参数,添加阶段写入向量,查询阶段返回近邻。Flat 不需要学习码本,IVF、PQ 通常需要先训练。索引训练与 embedding 模型训练是两个独立过程。入门教程

阅读源码时应留意 dntotalis_trainedmetric_type 等状态,以及不同子类对显式 ID、重建和删除的支持;基类存在某个接口不意味着所有实现均支持对应操作。Index 基类

4. 主要索引路线

索引 核心思路 主要代价 关注参数
Flat 比较全部原始向量 扫描量大 距离度量、批大小
IVFFlat 分桶后只扫描部分桶,桶内比较原始向量 可能漏掉未访问桶中的近邻 nlistnprobe
PQ 将子向量编码为码本编号 量化导致距离误差 子空间数 M、每段位数 nbits
IVFPQ IVF 缩小候选集,再使用 PQ 编码计算 候选遗漏与量化误差叠加 nlistnprobeMnbits
HNSWFlat 沿分层近邻图探索候选 额外图内存与构建成本 MefConstructionefSearch

IVF 的 nlist 决定分桶数量,nprobe 决定查询访问多少桶;PQ 的 M 和 HNSW 的 M 含义不同。Flat 可作为精确结果基线;扫描所有压缩编码的 PQ 仍可能产生近似结果。索引说明

建议先跑 Flat,确认数据与指标正确,再按瓶颈选择候选:内存充足、需要 CPU 低延迟时评估 HNSW;希望调节扫描范围时评估 IVF;内存紧张时评估量化方案。数据规模本身不足以决定索引,还需要考虑查询次数、训练成本与召回目标。官方选型指南

5. 容量估算

以下只计算主要向量载荷,不包含分配器、训练工作区、码本、图结构和服务进程开销:

表示方式 每条向量主要存储量
float32 Flat 4 × d 字节
IVFFlat 4 × d + 8 字节,包含存储的 ID
IVFPQ ceil(M × nbits / 8) + 8 字节

公式依据官方索引表。存储量说明

例如,一千万条 768 维向量的 float32 载荷为 10^7 × 768 × 4 = 30.72 GB,约 28.61 GiB。若使用 M=96、nbits=8 的 IVFPQ,编码及 ID 约为 10^7 × (96+8) = 1.04 GB,约 0.97 GiB。这是理论计算,不能直接当作进程内存峰值。

若需要原始向量精排,还必须计算原始向量的保留或外部读取成本。压缩索引变小,并不等于整个检索系统按相同比例缩小。

6. CPU/GPU 与性能关注点

CPU 距离计算可采用直接计算或 BLAS 路径。性能分析应分别观察距离计算、候选访问和 top-k 选择,并记录批大小及线程配置。实现说明

GPU 索引可接受主机或设备数据,并提供 CPU/GPU 索引转换接口。输入与索引位于同一 GPU 时可避免输入跨设备复制,但 CPU 与 GPU 索引的功能并非完全一致,应按目标版本核对具体 API。GPU 文档

当前官方仓库列出 CUDA、AMD ROCm 和可选 NVIDIA cuVS 后端;实际可用性取决于平台和构建配置。不能从“支持 GPU”推导出任意加速卡都能直接运行。构建与后端说明

针对性能研究或硬件移植,本文建议依次测量:

  1. Flat:分离距离计算与 top-k,建立正确性和吞吐基线。
  2. IVFFlat:加入粗量化、列表访问与候选合并,观察不规则访存。
  3. IVFPQ:测量查表、编码读取及精度损失。
  4. 端到端流程:加入数据搬运、批处理等待和结果回查,评估实际收益。

这是后续研究路线,不代表已经完成移植或获得加速结果。

7. 工程集成边界

问题 接入时需要确定的事项
ID 管理 顺序 ID 如何映射业务主键,是否需要显式 ID
更新与删除 目标索引支持哪些操作,外部映射如何维持一致
并发 区分并发只读与修改索引,单独设计 GPU 资源共享
持久化 索引文件、embedding 版本、业务映射和预处理参数一起管理
过滤 后过滤可能导致不足 k 条结果,需验证目标索引的过滤能力

官方 FAQ 说明 CPU 支持并发搜索,但并发搜索与添加、并发添加需要调用方同步;不要将该结论直接推广到 GPU。FAQ

Faiss 提供索引读写与克隆接口,GPU 索引写盘需要先转回 CPU。业务层仍需要设计一致性、版本切换与恢复流程。索引 IO

本文建议将 Faiss 作为服务中的检索组件评估。如果需求包含复杂元数据查询、权限、多副本和集群管理,应将外围系统的开发与维护成本一并计入选型。

8. 最小 API 示例

以下示例展示归一化后的内积精确检索。它是教学代码,本次未在文档构建环境中执行;运行时需另行安装 NumPy 和兼容的 Faiss CPU 包。Faiss 不属于本站构建依赖。

import numpy as np
import faiss

rng = np.random.default_rng(42)
xb = np.ascontiguousarray(rng.normal(size=(10_000, 128)), dtype=np.float32)
xq = np.ascontiguousarray(rng.normal(size=(100, 128)), dtype=np.float32)

# 实际数据应先检查 NaN、Inf 和零向量。
faiss.normalize_L2(xb)
faiss.normalize_L2(xq)

index = faiss.IndexFlatIP(xb.shape[1])
index.add(xb)
scores, ids = index.search(xq, 10)
assert ids.shape == (100, 10)
assert np.all((ids >= 0) & (ids < len(xb)))
print(ids[0], scores[0])

示例遵循官方 NumPy 输入及 add/search 用法。随机向量适合验证 API,不足以评估真实语义检索效果。入门教程

9. 可复现的实验方案

数据与环境

使用业务 embedding,分别准备训练集、入库集与查询集;存在时间分布变化时,保留较新的查询作评估。明确维度、距离、归一化、重复向量比例和过滤条件。

记录 Faiss 版本或 commit、硬件、线程数、BLAS、编译选项、数据摘要、随机种子和批大小。比较 CPU/GPU 时保持召回目标一致,并分别记录纯检索耗时和包含搬运的端到端耗时。

指标

本文将 Recall@k 定义为:对每条查询,近似结果与精确 top-k 集合的交集大小除以 k,再对查询取平均。参考集合由相同预处理及度量下的 Flat 生成,并统一并列距离的处理规则。

同时记录 QPS、请求延迟 p50/p95/p99、训练时间、入库时间、常驻及峰值内存、索引文件大小。批量总耗时除以查询数是摊销耗时,不能冒充单请求尾延迟。

首轮参数

以下是待验证的起点,需按数据与资源调整,不是通用最佳值。

方案 首轮参数
Flat batch = 1、32、256
IVFFlat nlist = 256、1024;nprobe = 1、4、16、64
IVFPQ 在 IVF 参数上选择能整除维度的 M;先用 nbits = 8
HNSWFlat M = 16、32;固定并记录 efConstruction,扫描 efSearch = 32、64、128

训练样本应足以支撑码本训练,并具有代表性。先以小规模验证流程,再扩大规模。建议比较固定内存预算下达到目标 Recall@k 的最低 p95,再观察吞吐。

索引及参数 Recall@10 p95 请求延迟 QPS 峰值内存 训练 / 入库时间
Flat 基线 待测 待测 待测 待测 待测
IVFFlat 待测 待测 待测 待测 待测
IVFPQ 待测 待测 待测 待测 待测
HNSWFlat 待测 待测 待测 待测 待测

10. 源码阅读与后续工作

建议先从官方 tutorial 复现最小流程,再以 Index.h 为入口,沿具体索引的 train/add/search 实现阅读。随后结合 Implementation notes 定位计算路径,最后阅读 GPU 资源与索引实现。

整体设计可配合项目作者的论文 The Faiss library 阅读。源码笔记应固定 commit,并针对具体索引记录调用链。

后续优先完成三项工作:确认数据规模和延迟目标;跑通 Flat 与一种近似索引的召回对比;使用 profiler 确认瓶颈后,再决定 GPU 优化或其他硬件适配方向。本文目前完成了资料调研和实验设计,尚不能给出特定业务下的性能优胜结论。