向量索引技术总结笔记
1. 向量索引基础概念
向量索引是一种特殊的数据结构,用于高效地存储、检索和比较高维向量数据,主要应用于相似性搜索场景。
向量索引配置示例
{
"meta": {"dvFormat": "Lucene70"},
"partition": 40,
"vector_type": "IVF",
"dims": 64,
"centroidNum": 256,
"nprobe": 4,
"metricType": "IP",
"centroidSql": "select vec from table where dt = $now.delta(1).datekey and rank_index_third_cate < 10 and vec <> '-1' limit 1000000"
}
关键参数解释
- dims: 向量维度
- centroidNum: 聚类中心点数量
- nprobe: 搜索时检查的聚类数量
- metricType: 相似度计算方法(IP=内积,L2=欧氏距离)
- centroidSql: 用于获取聚类中心点候选数据的SQL查询
2. 主要向量索引类型
IVF (Inverted File Index)
- 结构: 两层结构(聚类中心层 + 倒排列表层)
- 原理: 将向量空间分割成多个区域,查询时只在最相关的几个区域中搜索
- 优点: 简单高效,适合中等规模数据
- 缺点: 精度和速度的平衡不够灵活
IVF 索引的结构可以简单理解为"两层结构":
-
聚类中心层
- 组成:包含 centroidNum 个中心点向量(在配置中是256个)
- 每个中心点:是一个与原始向量维度相同的向量(在配置中是64维)
- 作用:将向量空间划分为不同的区域
-
倒排列表层
- 每个中心点:对应一个倒排列表
- 倒排列表:存储了分配到该中心点的所有向量的ID
- 可能还包含:向量与中心点的距离信息,用于优化搜索
IVF索引
├── 聚类中心层
│ ├── 中心点1
│ ├── 中心点2
│ ├── ...
│ └── 中心点N (N = centroidNum)
└── 倒排列表层
├── 列表1 → [向量ID_1_1, 向量ID_1_2, ...]
├── 列表2 → [向量ID_2_1, 向量ID_2_2, ...]
├── ...
└── 列表N → [向量ID_N_1, 向量ID_N_2, ...]
搜索过程可视化
当进行查询时:
- 计算查询向量与所有中心点的距离
- 选择最近的nprobe个中心点(在配置中是4个)
- 只在这些中心点对应的倒排列表中搜索
查询向量 → 计算与中心点距离 → 选择最近的4个中心点 → 在这4个列表中搜索 → 返回最相似的向量
这种结构大大减少了需要比较的向量数量,从而提高了搜索效率,尤其是在处理大规模向量数据时。
IVFPQ (IVF + Product Quantization)
- 结构: IVF结构 + 向量压缩编码
- 原理:
- 使用IVF进行粗筛选
- 将向量分段,每段用一个字节编码
- 大幅减少存储空间和计算量
- 优点: 极大节省存储空间,适合超大规模数据
- 缺点: 有一定精度损失
IVFPQ索引
├── 第一层:IVF聚类中心 (如256个)
│ ├── 中心点1 → 倒排列表1
│ ├── 中心点2 → 倒排列表2
│ └── ...
└── 第二层:每个向量的PQ编码
├── 向量1: [23, 45, 128, 67, 89, 12, 34, 56] // 8个字节的PQ编码
├── 向量2: [78, 34, 56, 89, 12, 45, 67, 23]
└── ...
搜索过程
当用户搜索相似商品时:
-
IVF过滤:
- 计算查询向量与256个中心点的距离
- 选择最近的4个中心点(nprobe=4)
- 只在这4个中心点对应的列表中搜索
-
PQ加速距离计算:
- 查询向量也被分成8段
- 预先计算每段与256个中心点的距离
- 通过查表快速计算与候选向量的近似距离
实际效果
- 存储减少:从每个向量256字节减少到8字节(压缩率32倍)
- 搜索加速:只需搜索约1.5%的数据(4/256),且距离计算更快
- 精度损失:会有一些精度损失,但对大多数应用来说可接受
这就像是图书馆不记录每本书的全文,而是用一个简短的"特征卡片"来代表每本书,大大节省了存储空间,同时也让查找变得更快。
HNSW (Hierarchical Navigable Small World)
- 结构: 多层图结构,类似"分层高速公路网络"
- 原理:
- 构建多层图,高层连接稀疏,低层连接密集
- 从顶层开始搜索,逐层下降
- 在底层进行精确搜索
- 优点: 搜索速度快,精度高,支持动态添加
- 缺点: 内存占用大,不支持向量压缩
HNSW 基本原理
HNSW 可以类比为一个"分层高速公路网络",从高速公路到乡村小路,层层递进。
核心结构
HNSW索引
├── 顶层(L2):稀疏连接的节点网络
│ ├── 节点A ──── 节点B
│ │ │
│ └── 节点C ──── 节点D
│
├── 中间层(L1):更多节点,更多连接
│ ├── 节点A ──── 节点B ──── 节点E
│ │ │ │ │
│ └── 节点C ──── 节点D ──── 节点F
│
└── 底层(L0):包含所有节点的密集网络
├── 节点A ──── 节点B ──── 节点E ──── 节点G
│ │ │ │ │
└── 节点C ──── 节点D ──── 节点F ──── 节点H
HNSW 工作流程
-
构建索引
- 分层结构:
- 创建多个层级(L0, L1, L2…)
- 底层(L0)包含所有向量
- 越高层包含的节点越少(通过随机抽样)
- 节点连接:
- 每个节点与同层的若干最相似节点建立连接
- 连接数由参数 M 控制(通常 M=16)
- 高层连接跨度大,低层连接更精细
- 插入新节点:
- 随机决定节点最高能到达的层级
- 从最高层开始,通过"贪婪搜索"找到每层最近的节点
- 与每层的最近节点建立双向连接
- 分层结构:
-
搜索过程
- 从顶层开始:
- 从顶层的随机入口点开始
- 在当前层进行"贪婪搜索",不断移动到更近的节点
- 直到无法找到更近的节点
- 逐层下降:
- 将上一层找到的最近节点作为下一层的入口点
- 在下一层继续贪婪搜索
- 重复直到到达底层(L0)
- 最终搜索:
- 在底层进行更精确的局部搜索
- 使用优先队列保存最近的 K 个节点
- 返回最终结果
- 从顶层开始:
具体例子
假设我们搜索与查询向量 Q 最相似的商品:
-
从顶层(L2)开始:
- 入口点:节点A
- 计算 Q 与 A 的距离: d(Q,A) = 0.8
- 检查 A 的邻居 B、C:d(Q,B) = 0.6, d(Q,C) = 0.9
- 移动到 B(更近)
- 检查 B 的邻居 D:d(Q,D) = 0.7
- B 仍是最近的,L2层搜索结束
-
下降到中间层(L1):
- 以 B 为入口点
- 检查 B 的邻居 A、D、E:d(Q,E) = 0.4
- 移动到 E
- 检查 E 的邻居 F:d(Q,F) = 0.5
- E 是最近的,L1层搜索结束
-
下降到底层(L0):
- 以 E 为入口点
- 检查 E 的邻居:发现 G 最近,d(Q,G) = 0.2
- 移动到 G
- 检查 G 的邻居:没有更近的了
- 返回 G 作为最终结果
3. 相似度计算方法
内积 (IP, Inner Product)
- 计算: 两个向量对应位置的乘积之和
- 特点: 更关注向量方向的一致性
- 应用: 常用于已归一化的向量
L2 距离 (欧氏距离)
- 计算: √[(A₁-B₁)² + (A₂-B₂)² + … + (Aₙ-Bₙ)²]
- 特点: 计算向量间的直线距离
- 应用: 更通用,适合多种场景
4. 向量索引构建过程
中心点生成
- 通过 centroidSql 获取候选向量数据
- 对候选向量进行聚类(如K-means算法)
- 得到 centroidNum 个中心点
索引构建
- IVF: 计算每个向量与中心点的距离,分配到最近的中心点
- IVFPQ: 额外进行向量压缩编码
- HNSW: 构建多层图结构,建立节点间连接
构建特点
- 索引构建是离线过程,通常耗时较长
- 中心点在索引构建阶段就已确定,检索时不再重新计算
- 构建质量直接影响检索效率和准确性
5. 向量索引与传统索引对比
与MySQL索引的区别
构建算法:
- MySQL: 基于排序构建B+树,确定性算法
- 向量索引: 基于聚类算法,涉及迭代优化
索引目的:
- MySQL: 加速精确匹配和范围查询
- 向量索引: 加速相似性搜索
查询机制:
- MySQL: 树遍历,精确匹配
- 向量索引: 近似最近邻搜索,权衡速度与准确性
实现层面:
- MySQL: 由InnoDB等存储引擎实现,标准化程度高
- 向量索引: 由各种专用库实现(Faiss, Milvus等),标准化程度低
6. 应用场景
- 图像搜索: 查找相似图片
- 推荐系统: 基于物品或用户向量的相似性推荐
- 语义搜索: 查找语义相似的文本
- 人脸识别: 匹配相似人脸
- 异常检测: 识别异常数据点
7. 性能优化考虑因素
- centroidNum: 增加可提高精度,但会降低速度
- nprobe: 增加可提高召回率,但会降低速度
- 向量维度: 降维可提高速度,但可能损失信息
- 中心点质量: 好的中心点分布可显著提升索引质量
- 向量压缩: 权衡存储空间与精度
向量索引技术是大规模相似性搜索的关键,选择合适的索引类型和参数配置对系统性能至关重要。