Faiss (Facebook AI Similarity Search) 是目前业界公认最强大的向量搜索库之一。在 Faiss 中,最基础也是最精确的索引类型是暴力检索索引(Flat Indexes),其中最常用的是 IndexFlatL2(欧氏距离)和 IndexFlatIP(内积)。
这篇文章将深入探讨这两种索引的核心逻辑,并提供可运行的 Python 代码示例,帮助您理解它们如何实现 100% 召回率的精确搜索。
1. 暴力检索的定义 (Flat Indexes)
“Flat” 意味着 Faiss 不会进行任何数据压缩或构建近似搜索所需的树状结构(如 HNSW 或 IVFFlat)。对于一个查询向量,它会计算该查询向量与数据库中所有向量的距离或相似度。虽然这在处理数十亿级数据时速度较慢,但它保证了搜索结果的绝对精确性(100% 召回)。
2. IndexFlatL2:欧氏距离(L2 Distance)
核心逻辑
IndexFlatL2 使用欧氏距离($L_2$ 范数距离)来衡量向量之间的不相似度。欧氏距离测量的是两个向量在多维空间中的直线距离。
$D_{L2}(x, y) = \sqrt{\sum_{i=1}^{d}(x_i – y_i)^2}$
关键点: 距离越小,相似度越高。Faiss 搜索结果返回的 $D$ 矩阵中存储的是距离的平方(为了避免开方运算加速计算,但排序结果一致)。
实操代码示例
首先确保安装了 faiss-cpu 和 numpy。
pip install faiss-cpu numpy
import faiss
import numpy as np
d = 64 # 向量维度
nb = 1000 # 数据库向量数量
nq = 1 # 查询向量数量
k = 5 # 返回Top-k结果
# 1. 生成模拟数据 (Float32是Faiss的标准)
np.random.seed(42)
xb = np.random.random((nb, d)).astype('float32')
xq = np.random.random((nq, d)).astype('float32')
# 2. 创建 IndexFlatL2 索引
index_l2 = faiss.IndexFlatL2(d)
# 3. 添加向量到索引
index_l2.add(xb)
# 4. 执行搜索
# D: 距离矩阵 (Distance), I: 索引矩阵 (Index)
# 距离D越小越好
D_l2, I_l2 = index_l2.search(xq, k)
print(f"--- IndexFlatL2 搜索结果 (L2 距离平方) ---")
print(f"最近 {k} 个向量的索引 (I): {I_l2[0]}")
print(f"对应的距离平方 (D): {D_l2[0]}")
3. IndexFlatIP:内积(Inner Product)
核心逻辑
IndexFlatIP 使用内积(点积)来衡量向量之间的相似度。内积是向量搜索中最常用的相似度度量之一,尤其适用于推荐系统和文本/图像嵌入。
$D_{IP}(x, y) = \sum_{i=1}^{d} x_i y_i$
关键点: 内积越大,相似度越高。如果所有向量都经过 L2 归一化,那么内积就等同于余弦相似度。Faiss 默认按内积值降序排序(即值越大越靠前)。
实操代码示例
为了演示 IP 索引,我们先对数据进行 L2 归一化,使其表现出余弦相似度的特性。
# 1. 重新使用原始数据 xb 和 xq
# 2. 对数据进行 L2 归一化 (让 IP = Cosine Similarity)
faiss.normalize_L2(xb)
faiss.normalize_L2(xq)
# 3. 创建 IndexFlatIP 索引
index_ip = faiss.IndexFlatIP(d)
# 4. 添加向量
index_ip.add(xb)
# 5. 执行搜索
# 距离D越大越好
D_ip, I_ip = index_ip.search(xq, k)
print(f"\n--- IndexFlatIP 搜索结果 (内积 / Cosine) ---")
print(f"最近 {k} 个向量的索引 (I): {I_ip[0]}")
print(f"对应的内积 (D): {D_ip[0]}")
4. 总结与应用场景选择
| 特性 | IndexFlatL2 | IndexFlatIP |
|---|---|---|
| 度量方法 | 欧氏距离 (Dissimilarity) | 内积 (Similarity) |
| 核心公式 | 距离的平方和 | 向量点积 |
| 排序原则 | 距离 D 越小越相似 | 相似度 D 越大越相似 |
| 适用场景 | 需要考虑向量绝对空间位置、物理距离的场景。 | 需要考虑向量方向、推荐系统、处理归一化嵌入向量的场景。 |
在选择暴力检索索引时,如果您的嵌入向量是基于深度学习模型产出且通常需要评估方向相似度(如 BERT, CLIP 等),那么经过归一化后的 IndexFlatIP(即余弦相似度)通常是首选。如果您的数据特性要求精确的空间距离度量,则应使用 IndexFlatL2。
汤不热吧