FAISS(Facebook AI Similarity Search)完整入门介绍

FAISS(Facebook AI Similarity Search)完整入门介绍

一、什么是 FAISS

FAISS = Facebook AI Similarity Search Meta(原 Facebook)开源的向量相似度检索库 ,核心用途: 在海量高维向量中快速搜索与目标向量最相似的向量(近似最近邻搜索 ANN)。

典型场景:RAG 检索、图片检索、音频检索、推荐系统、人脸比对、Embedding 向量匹配。

核心痛点解决

直接暴力遍历所有向量计算相似度(Brute-force):

  • 十万级向量尚可;百万、千万级向量速度极慢,无法线上使用 FAISS 使用近似最近邻算法 (ANN) ,牺牲极小精度,换取数十~上千倍检索加速

二、基础概念

1. 向量(Vector / Embedding)

文本 / 图像经过模型(BGE、CLIP、Sentence-BERT)编码得到固定长度浮点数数组,例如 [0.12,0.45,...],维度常见 384、768、1536。 向量越接近,代表原始内容语义越相似。

2. 距离度量(相似度计算)

FAISS 最常用两种:

  1. L2 距离(欧氏距离) 距离越小越相似。IndexFlatL2
  2. 内积 Inner Product(IP) 数值越大越相似,归一化向量等价于余弦相似度IndexFlatIP

RAG 工程最佳实践:将 embedding 归一化,使用 IndexFlatIP / IndexIVFFlat(IP) 等价余弦相似度,速度更快。

3. Index(索引)

FAISS 所有向量都存储在 Index 对象中,是最核心抽象:

  • 负责存储向量
  • 实现构建索引、添加向量、检索、保存 / 加载

三、各类 Index 选型(入门必看)

按复杂度、适用规模排序:

1. IndexFlatL2 / IndexFlatIP(暴力检索,精确搜索)

✅ 优点:结果 100% 准确,无参数调优,最简单 ❌ 缺点:向量量大时很慢 👉 适用:小于 1 万条向量、测试调试

复制代码
# 创建768维向量的暴力索引
import faiss
dim = 768
index = faiss.IndexFlatL2(dim)
# 归一化向量用余弦场景
# index = faiss.IndexFlatIP(dim)

2. IndexIVFFlat(倒排索引 IVF,工业最常用)

ANN 近似检索首选,中小规模(1 万~几百万向量) 原理:

  1. 先聚类(k-means)把向量划分成 nlist 个聚类中心(倒排单元)
  2. 查询时,只搜索距离查询向量最近的 nprobe 个聚类,不用遍历全部

关键超参:

  • nlist:聚类簇数量,经验公式 sqrt(N),N = 总向量数
  • nprobe:查询时检索多少个簇;越大精度越高,速度越慢(线上调参核心)

流程强制两步:先训练 (train) → 再 add 向量

复制代码
quantizer = faiss.IndexFlatL2(dim)
index = faiss.IndexIVFFlat(quantizer, dim, nlist, faiss.METRIC_L2)
index.train(train_vectors)  # 必须执行!
index.add(vectors)
index.nprobe = 10

3. IndexIVFPQ(IVF + PQ 乘积量化)

适合千万~亿级超大向量库 PQ:把高维向量压缩成短编码,大幅降低内存占用 代价:精度损失更大,需要调参,上手难度更高。

4. IndexHNSWFlat(HNSW 图索引)

基于层次导航小世界图,近年热门 ANN 算法 ✅ 检索速度很快,调参简单 ❌ 构建索引内存占用偏高 👉 适合百万级、追求查询延迟、内存充足的场景

四、最简可运行入门示例(Python)

安装

复制代码
# CPU版本
pip install faiss-cpu
# GPU版本(有Nvidia显卡)
pip install faiss-gpu

基础 Demo:建索引、添加、检索

复制代码
import faiss
import numpy as np

# 1. 参数设置
dim = 128       # 向量维度
nb = 10000      # 库内向量总数
nq = 5          # 查询向量数量
topk = 4        # 每个query返回最相似4条

# 2. 生成随机测试向量(实际替换为你的embedding)
np.random.seed(42)
xb = np.random.random((nb, dim)).astype('float32')  # 入库向量
xq = np.random.random((nq, dim)).astype('float32')  # 查询向量

# 3. 构建暴力索引
index = faiss.IndexFlatL2(dim)
print("索引是否训练完成:", index.is_trained)

# 4. 添加向量
index.add(xb)
print(f"索引内向量总数: {index.ntotal}")

# 5. 执行检索
D, I = index.search(xq, topk)
# D: 距离矩阵 [nq, topk]
# I: 向量下标矩阵 [nq, topk]

print("检索结果下标:\n", I[:3])
print("对应距离:\n", D[:3])

五、常用工程操作

1. 索引持久化(保存 & 加载)

复制代码
# 保存
faiss.write_index(index, "vector_index.index")
# 加载
index = faiss.read_index("vector_index.index")

2. 向量归一化(余弦相似度场景必备)

复制代码
faiss.normalize_L2(xb)
faiss.normalize_L2(xq)
index = faiss.IndexFlatIP(dim)

3. 映射 ID 问题(重要!)

FAISS 默认只返回数组下标,不是业务 ID。 当向量频繁增删,下标会混乱。 解决方案:

  1. 维护外部数组:id_map[faiss_idx] = 业务文档id

  2. 使用 IndexIDMap 包装索引,直接绑定自定义 ID

    base_index = faiss.IndexFlatIP(dim)
    index = faiss.IndexIDMap(base_index)

    add_with_ids(向量数组, 业务id数组)

    index.add_with_ids(vectors, np.array([1001,1002,1003]))

六、适用场景 & 局限

✅ 适合

  • RAG 知识库向量检索(LangChain/LlamaIndex 默认集成)
  • 图像、音频、多模态 Embedding 检索
  • 离线向量聚类、相似内容去重

❌ 局限

  1. 原生不支持动态高效删除 IVF/Flat 删除向量开销大;频繁删改建议:定期重建索引,或者使用向量数据库(Pinecone、Milvus、Chroma)
  2. 没有内置持久化、并发、分片、元数据过滤 FAISS = 检索算法库 ≠ 向量数据库

区分:FAISS 只是底层索引;Milvus/Chroma 是封装 FAISS,提供存储、并发、元数据过滤、分布式能力。

七、入门学习路线建议

  1. 先用 IndexFlat 跑通 Demo,理解向量检索输入输出
  2. 学习向量归一化 + IP 距离实现余弦相似度
  3. 上手 IndexIVFFlat,掌握 nlist/nprobe 调参,理解速度 / 精度权衡
  4. 学习 IndexIDMap 解决业务 ID 映射
  5. 海量向量再研究 PQ 量化、HNSW、GPU FAISS 加速
  6. 需要持久化、并发、过滤时,过渡到向量数据库

如果你需要,我可以提供:

  1. IVFFlat 完整调参模板
  2. 适配 LangChain 的 FAISS RAG 最小示例
  3. FAISS GPU 加速代码
  4. 对比:FAISS vs Chroma vs Milvus 选型参考
相关推荐
Zzzzzxl_8 个月前
互联网大厂Java/Agent面试实战:JVM、Spring Boot、微服务与RAG全栈问答
java·jvm·springboot·agent·rag·microservices·vectordb
Zzzzzxl_8 个月前
互联网大厂Java/Agent面试:Spring Boot、JVM、微服务、RAG与向量检索实战问答
java·jvm·spring boot·kafka·rag·microservices·vectordb
DolphinDB智臾科技2 年前
向量数据库、主键存储引擎、高速网络 RDMA 框架……DolphinDB 版本更新啦!
数据库·机器学习·时序数据库·ficc·dolphindb·vectordb