Faiss 向量数据库手册

向量数据库手册 03-向量索引库 17.7 KB 原文

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. 它是什么、什么时候选它
  2. 版本、许可与官方入口
  3. 安装与启动
  4. 核心概念与数据模型
  5. 快速上手:完整 CRUD 示例
  6. 索引与检索进阶
  7. 生产部署与运维
  8. 高频故障与排障
  9. 常见坑与避坑清单
  10. 速查表
  11. 参考与延伸

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-gpu wheel 自 v1.14.3 起新增、faiss-gpu-cuvs 自 v1.15.0 起新增,CPU 包与 GPU 包不要同时安装。faiss-cpu wheel 不含 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. 常见坑与避坑清单

  1. 现象:把 Faiss 当数据库,直接拿 I 当业务主键。原因:I 是 add 矩阵的行下标。怎么做:自己维护「下标 ↔ 业务 ID」映射,删改后同步重建。
  2. 现象:CPU 与 GPU 包同装后符号冲突。原因:三条包线不能共存。怎么做:一个虚拟环境只装一条,用第 2.3 节自检。
  3. 现象:add 抛 dtype 相关错误。原因:输入必须 float32。怎么做:统一 np.asarray(x, dtype="float32")。
  4. 现象:IVF/PQ add 报「未训练」类错误。原因:需要码本 / 聚类中心。怎么做:严格 train() → add(),训练样本要有代表性。
  5. 现象:距离阈值怎么设都不对。原因:IndexFlatL2 返回平方 L2。怎么做:比对前 np.sqrt(D),或按平方量纲设阈值。
  6. 现象:HNSW 上删除单条后结果异常。原因:HNSW 不支持删除向量。怎么做:改「标记删除 + 定期重建」,或换支持删除的库。
  7. 现象:上了 PQ 后召回明显掉。原因:PQ 有损压缩。怎么做:按第 6.3 节用 Flat 基线算 recall@k,调 nprobe / bit / 段数后再上线。
  8. 现象:带 category 过滤后一条不返回。原因:Faiss 无标量过滤,只能取回 top-k 后自己后过滤。怎么做:放大 k 再截断;高选择性过滤换 pre-filter 库。
  9. 现象:旧教程里装 faiss 就有 GPU 能力。原因:GPU wheel 后加(faiss-gpu v1.14.3 起、faiss-gpu-cuvs v1.15.0 起),faiss-cpu 不含 GPU 函数。怎么做:按当前包线选装,别照抄旧命令。
  10. 现象:多进程同时 write_index 把快照写坏。原因:无 WAL、无文件锁、整份覆盖写。怎么做:⚠️ 写临时文件 → 原子改名,保留上一版可回滚;多进程只读同一份文件。
  11. 现象:只备份索引文件,恢复后拿不回文档内容。原因:业务字段本就不在 Faiss 里。怎么做:索引文件与事实源一起备份,否则等于数据丢失。
  12. 现象:升级后加载旧索引失败。原因:跨版本索引格式兼容性未明确。怎么做:⚠️ 升级后用事实源重建索引,不要赌旧快照能直接加载。

⚠️ 危险:第 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 配对的读取函数名与参数 官方资料未逐字给出,以官方文档为准,本篇未臆造
Faiss 向量数据库手册 - 知识库 - 起航社区