Faiss 简介

FAISS(cpu,gpu)[Facebook AI Similarity Search]是针对海量稠密向量进行相似性搜索和聚类的一个高效类库。该开源库针对高维空间中的海量数据(稠密向量),提供了高效且可靠的相似性聚类和检索方法,可支持十亿级别向量的搜索,是目前最为成熟的近似近邻搜索库:官方资源地址https://github.com/facebookresearch/faiss

1.它包含可搜索任意大小的向量集的算法,这些向量集的大小甚至都不适合RAM。
2.它还包含用于评估和参数调整的支持代码。
3.Faiss用C ++编写,并且有python2与python3的封装代码。
4.一些最有用的算法在GPU上有实现。
5.Faiss是由Facebook AI Research开发的

本质上是一个 C++ 库(提供 Python 绑定),通常需要自行嵌入到应用中并管理存储和服务。极致的搜索速度和算法丰富性(专注于 ANN 算法),由 Meta 开发维护,社区活跃。FAISS不提供数据持久化,需结合其他存储系统。通过 API 调用搜索算法。适用于学术研究,算法实验,对搜索速度有极致要求的嵌入应用,需要高度自定义存储和服务的场景。主要关注 C++ 和 Python,需要自行处理存储、服务化等周边设施。

Faiss的核心

Faiss本质上是一个向量(矢量)数据库。进行搜索时,基础是原始向量数据库,基本单位是单个向量,默认输入一个向量x,返回和x最相似的k个向量。其中的核心就是索引(index对象),Index继承了一组向量库,作用是对原始向量集进行预处理和封装,一般操作包括train和add,可以建成一个索引对象缓存在计算机内存中。所有向量在建立前需要明确向量的维度d,大多数的索引还需要训练阶段来分析向量的分布(除了IndexFlatL2)。当索引被建立就可以进行后续的search操作了。
Train:
目的:生成原向量中心点,残差(向量中心点的差值)向量中心点,部分预计算的距离
流程:
1)把原始向量分成M个子空间,针对每个子空间训练中心点(如果每个子空间的中心点为n,则pq可表达n的M次方个中心点)。
2)查找向量对应的中心点
3)向量减去对应的中心点生成残差向量
4)针对残差向量生成二级量化器。
Search:
Search操作时索引的重要部分,search方法涉及实际的相似度计算,返回的检索结果包括两个矩阵,分别为xq中元素与近邻的距离大小和近邻向量的索引序号。

Faiss工作数据流

在使用Faiss进行query向量的相似性搜索之前,需要将原始的向量集构建封装成一个索引文件(index file)并缓存在内存中,提供实时的查询计算。在第一次构建索引文件的时候,需要经过Train和Add两个过程。后续如果有新的向量需要被添加到索引文件的话还可以有一个Add操作从而实现增量build索引。

  1. 索引构建(Indexing)

    • 读取文档库(如 PDF、TXT、Word 等)。
    • 使用嵌入模型(Embedding Model)将每一段文本转换为向量(vector)。
    • 使用 FAISS 将所有向量构建成一个索引(Index)。
    • 将 FAISS 索引保存到一个文件中(通常是 .index 文件)。同时,需要将文本内容(或指向原文的引用)及其对应的元数据(如文件名、标题、页码等)单独保存到另一个文件中(如 JSON、Parquet 或 pickle 文件)。这一步至关重要,因为 FAISS 只存储向量,不存储原始文本。
  2. 检索(Retrieval)

    • 加载 FAISS 索引文件和文本元数据文件到内存。
    • 当用户输入一个查询(关键字或问题)时,先用同样的嵌入模型将其转换为查询向量。
    • 使用 FAISS 的 search 方法,在索引中查找与查询向量最相似的 K 个向量。
    • FAISS 返回的是最相似向量的索引 ID 和相似度分数。
    • 根据这些索引 ID,去之前保存的文本元数据文件中找到对应的原始文本段落。
    • 将这些文本段落作为上下文,与用户问题一起发送给 LLM 生成最终答案。
  3. demo

import faiss
import numpy as np
from sentence_transformers import SentenceTransformer

"""
BEG模型
在MTEB/C-MTEB基准测试中综合排名第一,中文技术文档适配性最佳
提供多版本选择:bge-large-zh(1024维)、bge-base-zh(768维)、bge-small-zh(512维)
支持动态维度压缩技术,可在保持95%检索精度下将向量维度降低60%
集成Reranker模型,实现「召回+精排」两阶段优化流程

"""
encoder = SentenceTransformer('./model/bge-large-zh-v1.5')


def generate_embeddings(texts):
    """生成标准化的嵌入向量"""
    # 批量编码
    embeddings = encoder.encode(
        texts,
        convert_to_numpy=True,
        batch_size=32,
        show_progress_bar=False
    )
    # 转换为float32并L2归一化
    embeddings = embeddings.astype(np.float32)
    faiss.normalize_L2(embeddings)
    return embeddings


def reate_faiss_index(embeddings):
    """
    # 步骤3:构建FAISS索引
    :return:
    """

    dimension = embeddings.shape[1]  # 自动获取向量维度
    index = faiss.IndexFlatIP(dimension)  # 使用内积相似度
    index.add(embeddings)
    return index


def search(query, index, records, top_k=10):
    """执行语义搜索
	query: 需要检索的语句
	index: faiss构建的索引
	records: 构建索引的原始数据
	
	"""
    # 生成查询向量
    query_embedding = encoder.encode([query], convert_to_numpy=True)
    query_embedding = query_embedding.astype(np.float32)
    faiss.normalize_L2(query_embedding)

    # 执行搜索
    distances, indices = index.search(query_embedding, top_k)

    # 组装结果
    results = []
    for i, (score, idx) in enumerate(zip(distances[0], indices[0])):
        source = records[idx]
        results.append({
            "rank": i + 1,
            "score": float(score),
            "path": source["path"],
            "content": source["content"]
        })
    for i in results:
        print(i)

    return "\n\n".join([f"# {r.get('path')}\n{r.get('content')}" for r in results if r.get('score') > 0.5])	
	

这种方式的巨大优势

  • 极致的性能:FAISS 是为速度而生的,其搜索性能通常优于大多数通用的向量数据库。
  • 架构简单:系统中没有额外的外部数据库依赖,只有的应用和几个文件。这大大降低了部署和运维的复杂度。
  • 成本极低:完全免费,无需为数据库服务支付任何费用。
  • 轻量级:非常适合嵌入式部署、桌面应用或资源受限的环境。

局限性(也是考虑使用 Qdrant/LanceDB 等数据库的原因)

当的应用需求超出基本检索时,纯 FAISS 方案的短板就会显现:

  1. 元数据过滤(Metadata Filtering):

    • 问题:搜索“仅来自2023年财报PDF中、第二章的、与财务数据相关的内容”。这涉及到对文件名、日期、章节等多条件的过滤。
    • FAISS:无法实现。FAISS 只能做纯向量相似性搜索。必须先通过向量搜索出所有相似内容,然后在内存中自己对结果进行过滤,效率低下且不精确。
    • 向量数据库:原生支持。Qdrant 等可以在执行向量搜索的同时,精确地按元数据条件进行过滤,高效且准确。
  2. 动态更新(Dynamic Updates):

    • 问题:的文档库需要频繁增删改(例如,每天新增几篇新闻)。
    • FAISS:虽然支持增量添加,但每次添加新数据后,为了最优性能,通常需要重新生成整个索引并保存为新文件,这是一个很重的操作。
    • 向量数据库:原生支持实时、低延迟的单条数据插入、删除和更新,对应用层完全透明。
  3. 持久化与管理(Persistence & Management):

    • 问题:索引文件很大,如何版本化管理?如何备份?如何实现高可用?
    • FAISS:需要自己写脚本管理不同版本的 .index.json 文件,这很容易变得混乱。
    • 向量数据库:内置了数据持久化、备份、监控等功能,开箱即用。
  4. 多模态与生产级特性:

    • 问题:需要处理图片、视频等多模态数据,或者需要分布式、访问控制、API 接口等生产环境特性。
    • FAISS:不提供这些功能。
    • 向量数据库:LanceDB 天然支持多模态,Qdrant 等提供了完整的生产级分布式解决方案和 REST/gRPC API。

Faiss 索引

Faiss是为稠密向量提供高效相似度搜索的框架(Facebook AI Research),选择索引方式是faiss的核心内容,faiss 三个最常用的索引是:IndexFlatL2, IndexIVFFlat,IndexIVFPQ。

  • IndexFlatL2/ IndexFlatIP为最基础的精确查找。暴力精确检索,全局最优,适合数十万级。
  • IndexIVFFlat称为倒排文件索引,是使用K-means建立聚类中心,通过查询最近的聚类中心,比较聚类中的所有向量得到相似的向量,是一种加速搜索方法的索引。倒排暴力检索(100聚类后暴力检索),非全局最优但召回高,适合数百万级
  • IndexIVFPQ是一种减少内存的索引方式,IndexFlatL2和IndexIVFFlat都会全量存储所有的向量在内存中,面对大数据量,faiss提供一种基于Product Quantizer(乘积量化)的压缩算法编码向量到指定字节数来减少内存占用。但这种情况下,存储的向量是压缩过的,所以查询的距离也是近似的。检索复杂度log(logn),适合千万上亿规模以及更大规模的图索引,缺点是构建索引过程较慢,占用很大的存储。

总结与建议

特性 FAISS(独立文件模式) Qdrant / LanceDB 等向量数据库
核心功能 极速的向量相似性搜索 向量搜索 + 数据管理
架构 简单,无外部依赖 需要单独部署/维护数据库服务
元数据过滤 困难,需在内存中手动处理 原生支持,高效精确
动态更新 笨重,通常需全量重建 原生支持,实时高效
持久化与运维 需自行管理文件 内置,开箱即用
扩展性 有限 高(分布式、多模态、API等)

对于文档相对静态、不需要复杂元数据过滤、且追求简单性和极致性能的 RAG 项目,单独使用 FAISS 是最优解。如果项目出现以下需求时,才需要考虑升级到完整的向量数据库。

  1. 需要对搜索结果进行复杂的条件过滤。
  2. 文档库需要频繁、实时地更新。
  3. 系统需要扩展到分布式环境或需要高可用性。
  4. 不想手动处理索引文件和元数据文件之间的映射关系。

许多流行的 RAG 框架(如 LangChain, LlamaIndex)都同时支持 FAISS 和各类向量数据库,也印证了这两种方案在不同的场景下各有其不可替代的价值。


愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐