Faiss 向量数据库手册
Faiss 向量数据库手册
适用版本:v1.15.1(2026-09-16,核实于 2026-11);pip 包线
faiss-cpu/faiss-gpu/faiss-gpu-cuvs许可与形态:MIT(官方 LICENSE 正文未直接核验,见第 11 章);嵌入式 / 进程内索引库,不是数据库 一句话定位:只负责「把向量建成索引 + 算 top-k」,持久化、并发、鉴权、CRUD、分布式、元数据过滤全部由调用方自己实现 约定:$普通用户、#root 或 sudo、<xxx>为占位符;标 ⚠️ 的是高危操作。 更新时间:2026-11(版本与 API 变化快,执行前请以官方文档复核)
目录
1. 它是什么、什么时候选它
1.1 定位与架构
Faiss 是进程内的 C++ 库 + Python 绑定:没有守护进程、没有网络端口、没有存储引擎、没有用户体系。它在内存里维护一个 Index 对象,你把 float32 矩阵 add() 进去,它给你 search() 出 top-k 的距离与下标。一条检索链路里它只占中间一格:
| 层 | 谁负责 | Faiss 是否提供 |
|---|---|---|
| 文档 → Embedding 向量化 | 调用方 / 模型服务 | 不提供 |
| 向量 + 业务字段的事实源 | 调用方(库 / 文件 / 对象存储) | 不提供 |
| 建索引 + 算 top-k | Faiss | 唯一提供的一层 |
| 元数据 / 标量过滤 | 调用方自己写 | 不提供 |
| 持久化、快照、崩溃恢复、WAL | 调用方自己写 | 仅 faiss.write_index() 手动序列化 |
| 并发控制、鉴权、多租户 | 调用方自己写 | 不提供 |
| 分布式、分片、副本、扩缩容 | 调用方自己写 | 不提供 |
| 服务化(REST/gRPC)、SLA、监控 | 调用方自己写 | 不提供 |
避坑:把 Faiss 当数据库用是这类库最常见的事故来源。它返回「第几行向量最像」,不是「哪条业务记录最像」;下标与业务 ID 的映射、删除后的空洞、多进程写冲突,都要你自己兜住。
1.2 与同类产品的本质差别
| 对比项 | Faiss(索引库) | 真向量数据库(Milvus / Qdrant / Weaviate / pgvector) |
|---|---|---|
| 服务端进程 | 无,进程内对象 | 有 |
| 数据模型 | 只有 d 维 float32 矩阵 |
集合 / 字段 / 标量 / 主键 |
| 元数据过滤 | 无,需自己后过滤 | 原生 pre/post filter |
| 单条删除 | HNSW 不支持删除;Flat 侧需自己重建 | 原生 delete / upsert |
| 持久化与恢复 | 手动 write_index,无 WAL |
自动持久化、可恢复 |
| 鉴权 / 多租户 / RBAC | 无 | 有 |
| 水平扩展 | 无 | 分片 / 副本 / 分布式 |
| 适合角色 | 算法库、离线召回、嵌入其他系统 | 在线服务、RAG 生产链路 |
1.3 适合 / 不适合
适合:离线批量建索引与召回评测(拿 Flat 当 ground truth);数据量能装进单机内存且少变;作为自研检索系统的 ANN 内核;精细调优 IVF/PQ/HNSW 与量化对比实验;单进程脚本、端侧、无需服务化。
不适合:多进程 / 多机并发写与事务一致性;按标量字段做服务端过滤;单条即时删除 / 更新且马上生效;账号、权限、审计、TLS、多租户;崩溃自动恢复、弹性扩缩容、SLA 与告警;数据量超单机内存或需要分片副本。
1.4 规模与链路位置(经验值,非官方承诺)
| 量级 | 说明 |
|---|---|
| 百万级以内 × 768 维 | Flat 精确检索常可接受,建议先做基线 |
| 千万级 × 768 维 | 通常要 IVF / HNSW / PQ,Flat 全扫吃紧 |
| 亿级 | 单机内存一般放不下,需自己分片或换分布式库 |
| QPS / 维度 | 取决于索引、nprobe、机器,以实测为准;示例用 3~4 维,实际常见 768 / 1024 / 1536 |
Faiss 只承担「候选召回」:离线灌 embedding,在线取 top-k 下标,再回到自己的事实源取回文本与元数据做后过滤、重排、拼 prompt。RAG 的文档管理、增量更新、权限过滤全在 Faiss 之外。
⚠️ 危险:只把
I当业务 ID 用,一旦对底层矩阵做过删除、重排或重建,下标会整体错位,召回会静默串到错误文档。必须维护稳定的「下标 ↔ 业务 ID」映射,并在每次重建索引时同步重建。
1.5 什么时候该换真数据库(判断线)
出现任意一条且无法接受自研成本,就应改用真正的向量数据库或托管服务,别继续给 Faiss 打补丁:
| 触发条件 | 为什么 Faiss 兜不住 | 建议去处 |
|---|---|---|
| 多进程 / 多机并发写 | Index 是进程内对象,无跨进程锁与一致性 | Milvus / Qdrant / Weaviate / 云托管 |
| 需要服务端标量过滤(pre-filter) | 无元数据引擎,只能取回候选后自己后过滤 | pgvector / Qdrant / Milvus |
| 需要单条即时删除 / 更新 | HNSW 不支持删除;Flat 删除也要自己重建 | 真向量数据库 |
| 需要鉴权 / 多租户 / RBAC / 审计 | 无网络层、无用户概念 | 专用向量库或云托管 |
| 需要崩溃恢复 / 托管持久化 / WAL | write_index 只是手动快照 |
真向量数据库 |
| 数据量超单机内存 / 需要分片副本 | 单进程内存索引 | 分布式向量库 |
| 需要 REST/gRPC 服务、SLA、监控告警 | 完全没有服务化能力 | 真向量数据库 / 云托管 |
| 需要在线弹性扩缩容、免运维 | 需自己实现整套控制面 | 云托管(见 04 分册) |
2. 版本、许可与官方入口
2.1 版本状态表
| 版本号 | 时间 | 状态 | 备注 |
|---|---|---|---|
| v1.15.1 | 2026-09-16 | 当前核实版本 | 本手册依据 |
| v1.15.0 | 官方资料未给具体日期 | 历史 | 自该版起新增 faiss-gpu-cuvs wheel |
| v1.14.3 | 官方资料未给具体日期 | 历史 | 自该版起新增 faiss-gpu wheel |
2.2 许可与官方入口
- 许可:MIT(官方 LICENSE 正文未直接核验,见第 11 章;以官方仓库 LICENSE 为准)。开源库,无商业版 / 企业特性分层;真正的「商业边界」在于你要自己补齐的整套数据库能力,而非授权。
- 许可变更史官方资料未提供,以官方仓库为准。
| 类型 | 地址 |
|---|---|
| 官网 | https://faiss.ai |
| GitHub(源码 / Releases / INSTALL.md) | https://github.com/facebookresearch/faiss |
| PyPI 包名 | faiss-cpu / faiss-gpu / faiss-gpu-cuvs |
| conda 通道 | pytorch / conda-forge / nvidia / rapidsai |
2.3 版本识别与近两年变更
索引库没有服务端 --version,用 Python 侧自检能否 import、能否建索引:
$ python -c "import numpy as np, faiss; idx = faiss.IndexFlatL2(4); idx.add(np.zeros((1,4), dtype='float32')); D, I = idx.search(np.zeros((1,4), dtype='float32'), 1); print('faiss ok', D, I)"
版本差异:pip 包线从单一
faiss-cpu扩到三条 ——faiss-gpuwheel 自 v1.14.3 起新增、faiss-gpu-cuvs自 v1.15.0 起新增,CPU 包与 GPU 包不要同时安装。faiss-cpuwheel 不含 GPU 函数。官方资料未提供更早变更史,以官方 Releases / CHANGELOG 为准。
3. 安装与启动
3.1 前置条件与形态
Python + numpy;输入必须是连续 float32;GPU 包线需对应 CUDA / cuVS 环境(官方资料未给具体版本要求,以官方 INSTALL.md 为准)。无服务端、无端口、无守护进程,「启动」= 在进程里 import 并构造 Index。
3.2 方式一:conda(官方推荐,逐字取自官方 INSTALL.md)
$ conda install -c pytorch -c conda-forge faiss-cpu=1.15.1
$ conda install -c pytorch -c nvidia -c conda-forge faiss-gpu=1.15.1
$ conda install -c pytorch -c nvidia -c rapidsai -c conda-forge libnvjitlink faiss-gpu-cuvs=1.15.1
⚠️ 危险:三条是三选一,不是依次执行。CPU 包与 GPU 包不能共存,混装会导致符号冲突或 GPU 调用异常。
3.3 方式二:pip
$ pip install faiss-cpu
# 或(GPU 环境,二选一)
$ pip install faiss-gpu
$ pip install faiss-gpu-cuvs
避坑:三条包线的可用平台、wheel 与依赖差异较大(尤其
faiss-gpu-cuvs),包名与可用版本以 PyPI / 官方 INSTALL.md 为准;不要在同一虚拟环境里同时装faiss-cpu与faiss-gpu。
3.4 方式三:源码编译
官方资料未给出源码编译的逐字命令与 CMake 参数,请以官方 INSTALL.md 为准,本篇不臆造编译参数。
3.5 目录与端口表 / 健康检查 / 生产最小配置
| 项 | 值 / 做法 |
|---|---|
| 监听端口 | 无(进程内库,不监听端口) |
| 数据目录 | 调用方自定,write_index 输出到指定文件 |
| 健康检查 | python -c "import numpy as np, faiss; print('import ok')";或第 2.3 节一次验证 import + add + search |
| 认证 | 无原生能力,服务层套鉴权(见第 7 章) |
| 持久化路径 | 固定索引文件目录,write_index 后自行版本化与备份 |
| 资源限制 | 用容器 / cgroup 限内存;占用 ≈ 向量矩阵 + 索引结构,见第 6.5 节 |
4. 核心概念与数据模型
4.1 术语对照表
| Faiss 术语 | 通用术语 | 关系型类比 | 说明 |
|---|---|---|---|
Index |
索引对象 | 一张「索引」 | 进程内对象,非表 |
d |
向量维度 | 列宽 | 建 Index 时固定 |
add(xb) 的行 |
一条向量 | 一行记录 | 无显式主键,只有行下标 |
I(search 返回) |
近邻下标 | 行号 / rowid | 不是业务 ID |
D(search 返回) |
距离 | 打分 | L2 系越小越相似 |
4.2 数据模型与类型
Faiss 没有集合 / 数据库 / 字段 / schema 层级,只有一个 d 维 float32 矩阵;「表」完全由你在 Python 侧的 records 列表或外部数据库承担。
| 项 | 约束 |
|---|---|
| 元素类型 | 必须 float32;float64 / int / list 直接 add 会报错或产生错误结果 |
| 形状 | 二维连续数组 (n, d),维度与 add / search 一致 |
| 业务字段 | 不进 Faiss,自己存 |
4.3 距离度量、索引类型与生命周期
| 索引 | 工厂写法 | 度量 / 方向 | 是否需 train | 删除支持 |
|---|---|---|---|---|
IndexFlatL2(d) |
faiss.IndexFlatL2(d) |
L2,返回平方 L2,越小越相似 | 否 | 需自己重建 |
IndexHNSWFlat(d, 32) |
faiss.IndexHNSWFlat(d, 32) |
L2,越小越相似 | 否 | 不支持删除向量 |
IndexIVFPQ(quantizer, d, 1000, 16, 8) |
先建 quantizer 再建索引 | L2,越小越相似 | 是 | 需自己重建 |
生命周期:构造 Index →(IVF/PQ)train(xb) → add(xb) →(IVF)设 nprobe → search → write_index。全部同步、无异步 load。IVF/PQ 不 train() 直接 add() 会报错,训练样本要有代表性(官方示例 xb[:10000])。
避坑:
IndexFlatL2的D是平方 L2,不是欧氏距离本身。与别的系统比分数或设阈值前先开平方;直接把D当「距离」写进业务阈值会偏小。
4.4 D / I 与一致性模型
D, I = index.search(xq, k):
| 返回值 | 形状 | 含义 |
|---|---|---|
D |
(nq, k) |
距离矩阵;L2 系为平方 L2,越小越相似 |
I |
(nq, k) |
近邻在 add 矩阵中的行下标,不是业务 ID;无结果用 -1 填充 |
无事务、无 MVCC、无副本一致性。单进程内 add 后立即可见;多进程各持独立 Index,互不可见。一致性完全由调用方的「事实源 + 重建策略」决定。
⚠️ 危险:
I是行下标。删过数据、改过顺序、重建过索引之后旧下标会失效。永远用「下标 → 业务 ID」映射层取回记录,不要裸用I。
5. 快速上手:完整 CRUD 示例
说明:Faiss 没有「连接 / 表 / CRUD」概念。下面是你引入 Faiss 前必须自己维护的胶水层,Faiss 只替换其中「相似度检索」一步 —— 正好演示核心命题:CRUD、元数据过滤、持久化都是调用方的责任。
5.1 完整可运行示例(Python)
import numpy as np
import faiss
d = 4 # 示例用 4 维,实际常见 768 / 1024 / 1536
records = [
{"id": "doc-0", "text": "三国演义", "category": "history", "vec": [0.1, 0.2, 0.3, 0.4]},
{"id": "doc-1", "text": "红楼梦", "category": "history", "vec": [0.1, 0.2, 0.3, 0.5]},
{"id": "doc-2", "text": "三体", "category": "scifi", "vec": [0.9, 0.1, 0.2, 0.1]},
{"id": "doc-3", "text": "流浪地球", "category": "scifi", "vec": [0.8, 0.1, 0.2, 0.2]},
]
def build_index(rows):
"""C = 建集合 / U = 插入:Faiss 只吃 float32 连续矩阵,且无主键概念"""
xb = np.asarray([r["vec"] for r in rows], dtype="float32")
index = faiss.IndexFlatL2(d) # 精确基线
index.add(xb)
return index
def search_with_filter(index, rows, query_vec, category, k):
"""R + 带标量过滤检索:Faiss 无过滤能力,取回候选后自己后过滤"""
xq = np.asarray([query_vec], dtype="float32")
D, I = index.search(xq, k) # D 平方 L2,I 行下标
return [(rows[r]["id"], rows[r]["text"], float(dist))
for dist, r in zip(D[0], I[0])
if r >= 0 and rows[r]["category"] == category]
# 连接(嵌入式,仅 import)+ 创建集合 + 插入
index = build_index(records)
print("已灌入行数 =", len(records))
# R:相似度检索
D, I = index.search(np.asarray([[0.1, 0.2, 0.3, 0.45]], dtype="float32"), 2)
print("D(平方 L2) =", D, " I(行下标) =", I, " 首条 =", records[int(I[0][0])]["text"])
print("过滤 history =", search_with_filter(index, records, [0.1, 0.2, 0.3, 0.45], "history", 4))
# U:更新(Faiss 无行级 update,改事实源后重建索引)
records[1].update(text="红楼梦(修订)", vec=[0.1, 0.2, 0.3, 0.55])
index = build_index(records)
print("更新后检索 =", search_with_filter(index, records, [0.1, 0.2, 0.3, 0.55], "history", 2))
# D:删除(从事实源移除,再整表重建;HNSW 不支持删除,见第 9 章)
records = [r for r in records if r["id"] != "doc-3"]
index = build_index(records)
print("删除后剩余行数 =", len(records))
# 清理 / 持久化:手动序列化,无 WAL
faiss.write_index(index, "faiss_demo.index")
print("已写出 faiss_demo.index,加载请用官方配对的读取 API(见第 11 章)")
5.2 输出怎么读
D 是平方 L2(越小越像,阈值需自己开方换算),I 是 add 矩阵行下标(用 records[row] 回查业务记录,不是业务 ID);过滤 history 为后过滤结果 (业务ID, 文本, 平方L2);重建后旧下标全部失效。
避坑:官方最小形态是
flat = faiss.IndexFlatL2(d); flat.add(xb); D, I = flat.search(xq, 4),注释明确# D 是平方 L2。旧教程常把D当欧氏距离、把I当业务主键,两者都错。REST/cURL 不适用(无 HTTP 接口,见第 1.5 节);faiss-cpu不含 GPU 函数,GPU 路径需换 GPU 包线并用faiss.StandardGpuResources()+faiss.index_cpu_to_gpu(res, 0, index)。
6. 索引与检索进阶
6.1 索引参数调优表
| 参数 | 出现位置 | 官方示例值 | 影响 | 建议范围 |
|---|---|---|---|---|
d |
所有 Index 构造 | 64 | 向量维度,必须与数据一致 | 与 embedding 维度一致 |
| HNSW 连接数 | IndexHNSWFlat(d, 32) |
32 | 越大图越密、召回高、内存与构建慢 | 以实测为准 |
nlist |
IndexIVFPQ(..., 1000, ...) |
1000 | 聚类桶数 | 以实测为准 |
| 子向量数 | IndexIVFPQ(..., 16, 8) |
16 | PQ 分段数 | 以实测为准 |
| 每子向量 bit | IndexIVFPQ(..., 16, 8) |
8 | 码本大小 / 压缩比 / 精度 | 以实测为准 |
nprobe |
ivfpq.nprobe = 8 |
8 | 探测桶数,越大越准越慢 | 从小到大压测 |
「建议范围」为经验性表述,非官方承诺;官方资料未给出各参数默认值与推荐范围,以官方文档与实测为准。
6.2 召回 / 延迟 / 过滤 / 混合检索
nprobe调大 → 扫更多桶 → recall 上升、延迟上升;HNSW 连接数调大 → 图更密 → recall 上升、内存与构建时间上升;PQ 压缩比调高 → 内存下降、召回损失上升。没有统一最优值,必须用自己的数据压测 recall@k 与 p99。- Faiss 没有标量过滤,谈不上 pre/post。第 5 章演示的是调用方「先取回候选、再按元数据过滤」的后过滤。
⚠️ 危险:后过滤会让返回条数变少。
k取小、过滤条件又很 Selective 时可能一条不剩。生产上要么放大k再截断,要么换支持 pre-filter 的向量数据库。
- BM25 + 稠密混合、RRF 融合、稀疏向量、重排都要在外部自己实现 —— 同样是「索引库不是数据库」的直接后果。
6.3 用 Flat 基线测 PQ 召回损失
PQ 是有损压缩,官方明确「PQ 召回损失须自己用 Flat 基线测」:拿 Flat 的 I 当 ground truth,算 IVFPQ 的 I 命中率。
import numpy as np
import faiss
d, k = 64, 4
np.random.seed(0)
xb = np.random.random((10000, d)).astype("float32")
xq = np.random.random((200, d)).astype("float32")
flat = faiss.IndexFlatL2(d)
flat.add(xb)
D_flat, I_flat = flat.search(xq, k) # ground truth
quantizer = faiss.IndexFlatL2(d)
ivfpq = faiss.IndexIVFPQ(quantizer, d, 100, 16, 8)
ivfpq.train(xb[:5000]) # 必须先 train 再 add
ivfpq.add(xb)
ivfpq.nprobe = 8
D_pq, I_pq = ivfpq.search(xq, k)
hits = sum(sum(1 for v in I_pq[i] if int(v) in set(int(u) for u in I_flat[i]))
for i in range(xq.shape[0]))
print("recall@%d = %.4f" % (k, hits / (xq.shape[0] * k))) # 越接近 1 损失越小
避坑:换
nlist/ 子向量数 / bit /nprobe后都要重跑这段。不要凭「PQ 大概够用」上线量化索引。
6.4 内存与磁盘容量估算
- 原始向量矩阵:
n × d × 4字节(float32每元素 4 字节),再加索引结构开销。例:1,000,000 × 768 × 4 ≈ 2.86 GiB,这只是原始向量,HNSW 图 / IVF 码本 / PQ 码字另算。 - PQ 压缩后近似
n × 子向量数 × bit / 8字节(示例 16 段 × 8 bit = 16 字节/向量,相比 768×4=3072 字节压缩约 190 倍),但会损失召回。 write_index产物与内存索引同量级,无增量、无 WAL,每次落盘都是整份快照。以上为经验估算,以产物大小与free -m实测为准。
7. 生产部署与运维
7.1 把边界再讲透:Faiss 不负责什么
第 1 章列过分层,这里给出「坚持在生产用 Faiss 必须自己补齐什么」的落地清单:
| 缺失能力 | 自己要补的东西 |
|---|---|
| 持久化 | 定时 write_index + 文件版本化 + 异地备份 + 校验;配对加载函数以官方为准 |
| 并发 | 单写多读锁、进程间共享,或只读镜像 + 定期重建 |
| 鉴权 | 服务层做认证 / 授权 / 审计 / TLS,Faiss 完全不感知 |
| CRUD | 自己维护事实源,删除走「标记 + 定期重建」,HNSW 无删除 |
| 分布式 | 自己分片、聚合、路由、副本 |
| 元数据过滤 | 自己后过滤(第 6.2 节),或换支持 pre-filter 的库 |
| 服务化 | 自己包 REST/gRPC、连接池、超时、限流 |
| 监控 | 自己埋点:召回率、p99、add 行数、索引文件大小、内存 |
⚠️ 危险:多进程同时
write_index到同一路径会互相覆盖、损坏快照。落盘要「写临时文件 → 原子改名」,并保留上一版可回滚。
高可用 / 集群 / 分片 / 副本 Faiss 原生都不提供,可行做法都是调用方自建:多副本各持只读索引、前置负载均衡、定期全量重建后滚动替换。这与「托管服务买的是运维责任转移」形成鲜明对比 —— 这里责任全在你(对比见 04 分册)。
7.2 备份与恢复(索引是否需要重建)
| 项 | 做法 |
|---|---|
| 备份对象 | write_index 产出的索引文件 + 业务事实源(缺一不可) |
| 恢复 | 重新加载索引文件;加载 API 名以官方文档为准(见第 11 章) |
| 是否需要重建 | 只删标记 / 增量更新未进旧快照时必须重建;索引参数变更必须重建 |
| 恢复演练 | 定期用快照 + 事实源重建一遍并跑 recall 校验 |
避坑:不要只备份索引文件。没有事实源,你无法把
I(行下标)还原成业务记录,等于数据丢了。
7.3 监控指标与告警阈值建议 / 容量与升级
Faiss 无 /metrics 端点,需在服务层埋点:
| 指标 | 告警阈值建议(经验值) |
|---|---|
| 进程内存 | 超过容器 limit 的 80% 告警(OOM 是头号故障) |
单次 search p99 |
超过业务 SLO 告警 |
| recall@k(对比 Flat 基线) | 低于约定下限(如 0.95)告警 |
| 索引行数 vs 事实源行数 | 不一致即告警(下标错位前兆) |
write_index 产物大小 / 失败次数 |
突增或连续失败告警 |
| 后过滤命中率 | 过低说明 k 偏小或过滤过强 |
按第 6.4 节公式估算内存并预留索引结构与峰值余量;扩缩容 = 重建索引 + 换机器 / 换副本,无在线弹性,数据超单机内存就该分片或换库。升级:固定 conda / pip 版本(如 faiss-cpu=1.15.1),升级前用同一份数据跑 recall 对比;索引文件跨版本兼容性官方资料未提供说明,稳妥做法是升级后用事实源重建索引,GPU 包线升级还要核对 CUDA / cuVS 依赖,以官方 INSTALL.md 为准。
版本差异:
faiss-gpu(v1.14.3 起)、faiss-gpu-cuvs(v1.15.0 起)是后加的包线;老教程「装 faiss 就有 GPU」的说法已不成立。
7.4 安全基线与日志
| 面 | 建议 |
|---|---|
| 认证 / RBAC | 全部在服务层;Faiss 无用户概念 |
| TLS / 网络暴露面 | 进程内调用无需;理想暴露面为 0,别为调试把含 Faiss 的脚本直接暴露端口 |
| 索引文件权限 | 只读、最小权限;文件里可能含可反推的向量 |
| 输入校验 | 校验维度、dtype、k 上界,防畸形输入打爆内存 |
无自带日志,统一打到业务服务日志。系统级服务管理(systemd / 防火墙等)属通用运维,见根目录手册,本篇不重复。
8. 高频故障与排障
| 症状 | 可能原因 | 定位命令 / 方法 | 处置 |
|---|---|---|---|
| 连不上 / 服务无响应 | 把 Faiss 当服务了,其实没有监听端口 | 查端口 + 第 2.3 节自检 | 改进程内调用;需要服务化就换真数据库 |
import faiss 失败 / 符号冲突 |
CPU 与 GPU 包混装 | pip list | grep faiss |
卸载到只剩一条包线,重建虚拟环境 |
StandardGpuResources 不存在 |
装了 faiss-cpu(不含 GPU 函数) |
第 2.3 节自检 + 查包名 | 换 faiss-gpu / faiss-gpu-cuvs,勿与 CPU 包共存 |
| 写入失败:dtype / 维度错 | 输入不是 float32 或形状不是 (n, d) |
打印 xb.dtype、xb.shape |
np.asarray(..., dtype="float32"),维度对齐 d |
| 查不到 / 召回低 | nprobe 太小、PQ 压缩过狠、后过滤把结果滤光 |
第 6.3 节 Flat 基线算 recall;放大 k |
调大 nprobe、降压缩比、放大候选 k 或换 pre-filter 库 |
| 查询慢 | 用了 Flat 全扫,或 nprobe 过大 |
计时 search,对比 Flat 与 ANN |
换 IVF/HNSW/PQ,压测调 nprobe |
| OOM | 向量矩阵 + 索引结构超单机内存 | free -m;按第 6.4 节估算 |
量化(PQ)、分片、减副本、换分布式库 |
| 磁盘满 / 索引不生效 | write_index 整份快照多版本累积;加载了旧快照 |
df -h;对比 I 与 Flat 基线 |
只保留最近 N 版;重建索引、确认加载新文件 |
| 版本升级后报错 | 索引文件跨版本不兼容 / GPU 依赖变了 | 固定版本复现;查 Releases | 用事实源重建索引,核对 CUDA/cuVS 依赖 |
| 过滤结果变少 / 删除后串位 | 后过滤在 k 之后执行;HNSW 删除或重建后旧下标未失效 |
打印过滤前后条数;比对事实源行数 | 放大 k 再截断;HNSW 不做删除,重建索引同时重建「下标→ID」映射 |
9. 常见坑与避坑清单
- 现象:把 Faiss 当数据库,直接拿
I当业务主键。原因:I是add矩阵的行下标。怎么做:自己维护「下标 ↔ 业务 ID」映射,删改后同步重建。 - 现象:CPU 与 GPU 包同装后符号冲突。原因:三条包线不能共存。怎么做:一个虚拟环境只装一条,用第 2.3 节自检。
- 现象:
add抛 dtype 相关错误。原因:输入必须float32。怎么做:统一np.asarray(x, dtype="float32")。 - 现象:IVF/PQ
add报「未训练」类错误。原因:需要码本 / 聚类中心。怎么做:严格train()→add(),训练样本要有代表性。 - 现象:距离阈值怎么设都不对。原因:
IndexFlatL2返回平方 L2。怎么做:比对前np.sqrt(D),或按平方量纲设阈值。 - 现象:HNSW 上删除单条后结果异常。原因:HNSW 不支持删除向量。怎么做:改「标记删除 + 定期重建」,或换支持删除的库。
- 现象:上了 PQ 后召回明显掉。原因:PQ 有损压缩。怎么做:按第 6.3 节用 Flat 基线算 recall@k,调
nprobe/ bit / 段数后再上线。 - 现象:带
category过滤后一条不返回。原因:Faiss 无标量过滤,只能取回 top-k 后自己后过滤。怎么做:放大k再截断;高选择性过滤换 pre-filter 库。 - 现象:旧教程里装
faiss就有 GPU 能力。原因:GPU wheel 后加(faiss-gpuv1.14.3 起、faiss-gpu-cuvsv1.15.0 起),faiss-cpu不含 GPU 函数。怎么做:按当前包线选装,别照抄旧命令。 - 现象:多进程同时
write_index把快照写坏。原因:无 WAL、无文件锁、整份覆盖写。怎么做:⚠️ 写临时文件 → 原子改名,保留上一版可回滚;多进程只读同一份文件。 - 现象:只备份索引文件,恢复后拿不回文档内容。原因:业务字段本就不在 Faiss 里。怎么做:索引文件与事实源一起备份,否则等于数据丢失。
- 现象:升级后加载旧索引失败。原因:跨版本索引格式兼容性未明确。怎么做:⚠️ 升级后用事实源重建索引,不要赌旧快照能直接加载。
⚠️ 危险:第 10、11、12 条都可能导致线上数据丢失或长期静默错误结果,上线前必须做恢复演练与 recall 回归。
10. 速查表
| 操作 | 命令 / 代码 | 说明 |
|---|---|---|
| 安装 CPU(conda) | conda install -c pytorch -c conda-forge faiss-cpu=1.15.1 |
官方推荐 |
| 安装 GPU(conda) | conda install -c pytorch -c nvidia -c conda-forge faiss-gpu=1.15.1 |
与 CPU 包二选一 |
| 安装 cuVS(conda) | conda install -c pytorch -c nvidia -c rapidsai -c conda-forge libnvjitlink faiss-gpu-cuvs=1.15.1 |
三选一 |
| 安装 CPU(pip) | pip install faiss-cpu |
包名以 PyPI 为准 |
| 自检 import | python -c "import numpy as np, faiss; print('ok')" |
无服务端版本命令 |
| 建精确索引 | index = faiss.IndexFlatL2(d) |
返回平方 L2 |
| 建 HNSW | index = faiss.IndexHNSWFlat(d, 32) |
不支持删除 |
| 建 IVF+PQ | faiss.IndexIVFPQ(faiss.IndexFlatL2(d), d, 1000, 16, 8) |
需先 train |
| 强制 float32 | xb = np.asarray(x, dtype="float32") |
输入硬性要求 |
| 训练 | ivfpq.train(xb[:10000]) |
IVF/PQ 必做 |
| 灌数据 | index.add(xb) |
train 之后 |
| 设探测桶数 | ivfpq.nprobe = 8 |
越大越准越慢 |
| 检索 | D, I = index.search(xq, 4) |
D 距离、I 行下标 |
| 读结果 | records[int(I[0][0])] |
I 不是业务 ID |
| 开方还原距离 | np.sqrt(D) |
Flat L2 返回平方值 |
| recall 基线 | faiss.IndexFlatL2(d) + search |
拿 I 当 ground truth |
| 落盘 | faiss.write_index(index, "index.bin") |
手动快照,无 WAL |
| 加载 | 以官方文档配对读取 API 为准 | 见第 11 章 |
| GPU 资源 / 迁 GPU | faiss.StandardGpuResources() / faiss.index_cpu_to_gpu(res, 0, index) |
仅 GPU 包线 |
| 换真数据库 | 见第 1.5 节判断线 | 别硬撑 |
常用端口与路径小表
| 项 | 值 |
|---|---|
| 网络端口 | 无(进程内库) |
| GPU 设备号 | 示例 0(index_cpu_to_gpu(res, 0, index)) |
| 索引文件示例 | index.bin / faiss_demo.index(调用方自定) |
| 官方入口 | https://faiss.ai | https://github.com/facebookresearch/faiss |
11. 参考与延伸
11.1 官方文档链接清单
| 内容 | 地址 |
|---|---|
| 官网 | https://faiss.ai |
| 源码 / Releases / INSTALL.md | https://github.com/facebookresearch/faiss |
| pip 包线说明 | 官方 INSTALL.md(见上方仓库) |
11.2 与本册其他产品的关系
- 同属「向量索引库(不是数据库)」:hnswlib-Annoy-ScaNN.md,三库对照见该篇。
- 出现第 1.5 节任一判断线时,改用真向量数据库:Milvus / Qdrant / Weaviate / pgvector(见对应分册)。
- 想买「运维责任转移」而非自建,见 04 分册:
Pinecone.md、Zilliz-Cloud.md、国内云向量数据库.md。
11.3 进阶阅读方向
IVF / PQ / HNSW 参数对 recall 与延迟的量化影响;以 Flat 为 ground truth 的 recall@k 评测方法学;索引文件版本化、原子发布与回滚;从 Faiss 迁移到支持 pre-filter / 删除 / 分布式向量库的改造路径。
11.4 本篇「未核实 / 以官方为准」事项
| 事项 | 状态 |
|---|---|
| Faiss 官方 LICENSE 正文 | 未核实(官方资料标注「MIT,官方 LICENSE 正文未直接核验」);本篇仅按官方资料标注 MIT,正文条款以官方仓库 LICENSE 为准 |
| v1.15.0 / v1.14.3 的具体发布日期 | 官方资料未提供,以官方 Releases 为准 |
faiss.write_index 配对的读取函数名与参数 |
官方资料未逐字给出,以官方文档为准,本篇未臆造 |