跳转至

二十九:向量索引

来源:http://mp.weixin.qq.com/s?__biz=MzYyNTk3Njg1NA==&mid=2247484333&idx=1&sn=1d01f1edb0ec237ac8c18618177fa0df&chksm=f01eb0d4c76939c21df08002097d2538a355e4b6370b8a3d4795c698324400faa0547640b3b1#rd

1. 学习范围

本日主题是向量索引,重点是 IVF_FLAT 和 HNSW。向量索引是 RAG、推荐、语义搜索、多模态检索中的核心基础设施。它解决的问题是:当向量数量很大时,如何在可接受延迟和资源成本下找到与 query 向量最相近的候选。 本日覆盖: - 向量检索和最近邻搜索的基本定义。

  • 精确搜索与近似最近邻搜索 ANN。

  • 相似度指标:L2、Inner Product、Cosine。

  • Flat 索引、IVF_FLAT、HNSW 的原理和参数。

  • IVF_FLAT 的聚类、nlist、nprobe、召回率和延迟权衡。

  • HNSW 的图结构、M、efConstruction、efSearch、召回率和内存权衡。

  • 索引选择、调参、评估、生产化和 RAG 场景应用。

2. 向量检索的问题定义

给定一组向量:

D = {x1, x2, ..., xn}, xi in R^d
给定 query 向量:

q in R^d
向量检索要找到与 q 最相似(例如余弦相似度)的 top-k 向量:

top-k argmax sim(q, xi)
或在距离度量下(例如欧氏距离)找到最近的 top-k:

top-k argmin dist(q, xi)
RAG 中,向量通常来自 embedding 模型,文档 chunk 和 query 被映射到同一向量空间。

3. 相似度指标

常见指标包括:

3.1 L2 Distance 欧氏距离

L2(q, x) = ||q - x||_2
距离越小越相似。

3.2 Inner Product 内积

IP(q, x) = q · x
内积越大越相似。适合某些 embedding 或推荐向量。

3.3 Cosine Similarity 余弦相似度

cos(q, x) = q · x / (||q|| ||x||)
衡量方向相似度。如果向量都归一化,cosine similarity 与 inner product 排序等价。 选择指标必须与 embedding 模型训练方式一致。指标选错会明显降低召回质量。

4. 精确搜索与 ANN

精确搜索会计算 query 与全部向量的相似度,找到真正 top-k。优点是准确,缺点是大规模数据下延迟高。 复杂度大致为:

O(N * D)
N 达到百万、千万甚至更大时,每次都全量扫描成本很高。ANN, Approximate Nearest Neighbor,近似最近邻检索, 通过索引结构减少搜索范围,用可控的召回率损失换取速度和内存效率。

核心思想

预先构建专用索引结构,将高维向量空间做划分、编码或分层映射;检索时仅在少量候选分区内做局部比对,跳过绝大多数无关向量,以可控、小幅的召回率损失,换取检索速度、内存占用的大幅优化。 ANN 的核心权衡: - recall。

  • latency。

  • memory。

  • build time。

  • update cost。

  • filtering support。

通俗理解:

一、精确搜索(暴力检索 Brute Force)是怎么做的?

假设你有一个向量库,一共 1000 万条文档向量,用户输入一段提问 q。精确搜索逻辑:把 q 和库里每一条向量全部算一遍相似度,1000 万次计算,再排序选出最像的前 k 个。优点:一定找到真正最相似的 k 个,不漏;缺点:数量一大算得巨慢,线上问答、RAG 根本扛不住。 类比生活化例子:全班 10000 个学生,老师要找出和你长得最像的 3 个人。精确搜索 = 你挨个和全班每个人对比长相,全部比完再选出前三名。人越多,对比时间越长。

二、ANN 全称:Approximate Nearest Neighbor 近似最近邻

核心一句话:不跟所有人对比,只对比一小部分人,牺牲一点点准确率,换极快的速度。关键词:近似 ≠ 百分百准确,可控丢一点召回,换速度。 还是上面班级例子:老师提前把全班按地域分组:北京组、上海组、广东组、四川组……你是北京人,老师直接只拿「北京组」的同学和你对比,跳过全国其他几千人。大概率和你长得像的人都在北京组,只会极少数长得像但外地的人漏掉。 - 好处:对比人数大幅减少,速度飞快;

  • 代价:有极小概率漏掉真正最像的几个人;这就是 ANN 的核心思路。

放到向量空间里翻译:高维向量空间提前做分区 / 分层 / 编码(索引),查询时只在少数分区内部计算相似度,跳过绝大多数无关向量,计算量大幅下降。

三、为什么叫「近似」?什么是召回损失?

举数字直观理解:真实最优 top5 文档是 A/B/C/D/E。 - 精确检索:返回 [A,B,C,D,E],召回率 100%;

  • ANN 检索:只搜到 [A,B,C,D,F],漏掉 E,召回率 80%。E 是真正近邻,但因为只检索了局部分区,没扫到,这就是近似带来的微小精度损耗。

工程上我们可以调索引参数,控制损耗大小: - 参数调保守:召回 98%,速度中等;

  • 参数调激进:召回 85%,速度极快;业务根据需求取舍:RAG 一般接受 90%+ 召回,换取毫秒级检索。

四、ANN 索引是怎么缩小搜索范围的(3 种主流思路)

1. 聚类分区 IVF(倒排文件)

离线阶段:把所有向量聚类成几百 / 几千个簇中心。检索:只找和查询向量最接近的几个簇,只在这几个簇内部计算相似度,其余簇直接抛弃。

2. 分层图索引 HNSW(最常用 RAG 索引)

离线构建一张多层有向图,相近向量互相连边。检索从顶层粗略跳转,逐层往下细化,全程只遍历少量邻居节点,不用扫描全量。

3. 向量量化 PQ(乘积量化,压缩内存)

把向量拆成小段压缩存储,用近似距离代替精确距离计算,既省内存又提速。

五、再梳理 ANN 的六大权衡(结合例子更好懂)

  • Recall 召回率想越高越准,就要多扫描分区 / 多遍历节点,速度变慢;反之速度快但容易漏文档。

  • Latency 检索延迟用户等待时间,线上系统硬性要求,ANN 核心目标就是压低延迟。

  • Memory 内存HNSW 图索引占用内存高;PQ 量化索引占用极低,适合亿级海量向量。

  • Build time 建索引时间千万级向量构建 HNSW 很慢;IVF 聚类构建速度更快。

  • Update cost 更新成本频繁新增、删除文档场景:IVF 增量更新友好;HNSW 大量删除后索引效率暴跌。

  • Filtering support 元数据过滤比如只检索 2025 年的文档、只检索法律类文本;部分索引不支持前置过滤,只能检索完再过滤,会降低有效召回。

5. Flat 索引

Flat 索引保存所有原始向量,查询时全量比较。 Flat 索引直接完整存储全部原始向量,不做空间划分、量化、图结构等任何索引预处理。检索流程等价于精确暴力搜索:查询向量 q 与库内每一条向量逐一计算距离 / 相似度,全局排序后输出真实 Top-k。时间复杂度:O(N · d),N 向量总数,d 向量维度。 优点: - 精确 top-k。

  • 实现简单。

  • 不需要训练。

  • 适合作为评估基线。

缺点: - 查询延迟随数据量线性增长。

  • 大规模数据成本高。

Flat 适合: - 小规模数据。

  • 高精度评估。

  • GPU 加速下的中等规模检索。

  • ANN 索引 recall 对比基线。

6. IVF 的基本思想

IVF, Inverted File Index, 是向量检索中的倒排索引思想。它先用聚类把向量空间划分为多个区域,每个区域对应一个 list。 离线阶段:

1. 用 k-means 学习 nlist 个聚类中心。
2. 将每个向量分配到最近的聚类中心。
3. 每个聚类中心维护一个 inverted list。
每个簇中心绑定一条倒排列表,表内存放所有归属该簇的原始向量;最终形成「簇中心 → 簇内向量列表」的映射关系。 查询阶段:

1. 找 query 最近的 nprobe 个聚类中心。
2. 只在这些 inverted lists 中搜索。
3. 返回 top-k。
IVF 的核心是减少候选数量:不用扫描全部向量,只扫描 query 附近的若干簇。

7. IVF_FLAT

IVF_FLAT 是 IVF + 原始向量存储。它使用 IVF 缩小候选范围,但在被选中的 inverted lists 中仍使用原始向量做精确距离计算。 结构:

coarse quantizer: 聚类中心
inverted lists: 每个 list 存原始向量 ID 和原始向量
优点: - 比 Flat 快。

  • 候选 list 内使用原始向量,精度高于量化压缩方案。

  • 参数相对容易理解。

缺点: - 需要训练聚类中心。

  • recall 受 nlist/nprobe 影响。

  • 如果数据分布不均,部分 list 过大。

  • 内存仍需保存原始向量。

8. IVF_FLAT 关键参数

8.1 nlist

nlist 是聚类中心数量,也就是 inverted lists 数量。 - nlist 太小:每个 list 很大,查询慢。

  • nlist 太大:训练成本高,list 可能过稀,可能影响召回。

8.2 nprobe

nprobe 是查询时扫描的聚类中心数量。 - nprobe 越大:扫描更多 list,recall 更高,延迟更高。

  • nprobe 越小:查询更快,但可能漏掉真实近邻。

IVF_FLAT 的核心调参就是 nlist 和 nprobe 的权衡。

9. IVF_FLAT 的召回率与延迟权衡

如果 nprobe = nlist,理论上扫描所有 list,接近 Flat 精确搜索,但速度优势消失。 如果 nprobe 很小,速度快,但真实近邻可能位于未扫描的 list 中。 调参流程: - 用 Flat 建立 ground truth。

  • 对不同 nlist/nprobe 组合测试 Recall@k。

  • 记录平均延迟、P95 延迟和内存。

  • 选择满足业务 recall 的最低延迟配置。

RAG 通常更关注 recall,因为正确文档漏召回后生成阶段无法补救。

10. IVF 的训练与数据分布

IVF 需要用训练数据学习聚类中心。训练数据应代表真实向量分布。 常见问题: - 训练样本太少,聚类中心不稳定。

  • 数据分布变化后索引质量下降。

  • list 分布不均,热点 list 过大。

  • 新数据持续加入导致聚类中心过时。

生产系统中应监控 list size 分布、查询延迟和 recall,必要时重建索引。

11. HNSW 的基本思想

HNSW, Hierarchical Navigable Small World,分层导航小世界图,是基于图的 ANN 索引。它构建一个多层近邻图,高层图稀疏、用于快速跳转,底层图密集、用于精细搜索。 直观类比:

高层:高速公路,快速接近目标区域
底层:城市道路,局部精细搜索
查询从最高层入口点开始,逐层贪心搜索,最后在底层找到近邻。

12. HNSW 图结构

感兴趣详细构建和搜索,可以详见:https://milvus.io/docs/zh/hnsw.md HNSW 每个节点是一个向量。节点会与若干近邻建立边。层数通常随机分配,少数节点出现在高层,大多数节点只在底层。 建立图的过程: 搜索过程:

1. 从入口点进入最高层。
2. 在当前层贪心移动到更接近 query 的节点。
3. 下到下一层继续搜索。
4. 在底层用候选队列扩展搜索,返回 top-k。
图结构让查询不需要扫描全部向量,而是沿近邻边快速接近目标区域。

13. HNSW 关键参数

13.1 M

M 控制每个节点最大连接数。 - M 越大:图更密,recall 更高,内存更大,构建更慢。

  • M 越小:内存少,速度可能快,但 recall 下降。

13.2 efConstruction

构建索引时使用的候选队列大小。 - efConstruction 越大:图质量更高,构建更慢。

  • efConstruction 越小:构建快,但 recall 可能差。

13.3 efSearch

查询时搜索候选队列大小。 - efSearch 越大:recall 更高,延迟更高。

  • efSearch 越小:速度快,但可能漏召回。

HNSW 调参核心是 M、efConstruction、efSearch。

14. HNSW 的召回率与内存权衡

HNSW 通常 recall 高、查询速度快,尤其适合内存充足、低延迟要求高的场景。但它的图边需要额外内存,内存开销通常高于 IVF_FLAT。 典型权衡: - 追求高 recall:增大 M 和 efSearch。

  • 控制内存:降低 M。

  • 控制构建时间:降低 efConstruction。

  • 控制查询延迟:降低 efSearch。

在 RAG 中,HNSW 常作为高质量默认 ANN 方案,但数据量极大或内存受限时要谨慎。

15. IVF_FLAT 与 HNSW 对比

IVF_FLAT: - 基于聚类和倒排表。

  • 内存保存原始向量,额外结构相对可控。

  • 查询通过 nprobe 扫描部分簇。

  • 适合大规模、可接受训练和调参的场景。

  • recall 受聚类质量影响。

HNSW: - 基于多层近邻图。

  • 查询速度快,recall 通常高。

  • 内存开销较大。

  • 动态插入通常较自然,但删除和压缩要看实现。

  • 参数 M/efSearch 对性能影响明显。

选择时要看数据规模、内存、延迟、更新、过滤和 recall 要求。

16. 过滤与向量索引

RAG 中经常需要按 metadata 过滤,例如权限、部门、时间、语言、文档类型。过滤与 ANN 索引结合是工程难点。 常见策略: - 先过滤后向量检索:精确但候选可能太少或慢。

  • 先向量检索后过滤:快但可能过滤后结果不足。

  • 分区索引:按租户/部门/语言分索引。

  • 标量过滤下推:由向量数据库支持。

权限过滤必须可靠。不能先检索无权文档再让模型不要泄露。

17. 索引更新与删除

生产系统需要支持: - 新文档插入。

  • 旧文档更新。

  • 文档删除。

  • 权限变化。

  • embedding 模型升级。

索引更新策略: - 小规模实时 upsert。

  • 定期批量重建。

  • 双索引切换。

  • 增量索引 + 后台 compaction。

embedding 模型升级通常需要全量重新 embedding 和重建索引,因为向量空间变了。

18. 评估指标

向量索引评估通常包括: - Recall@k。

  • QPS。

  • 平均延迟。

  • P95/P99 延迟。

  • 内存占用。

  • 构建时间。

  • 更新延迟。

  • 过滤后召回率。

ANN 索引评估要与 Flat ground truth 对比。对于 RAG,还要看最终答案正确率和证据召回率。

19. RAG 中的索引选择

小规模知识库: - Flat 或 HNSW。

中等规模、低延迟: - HNSW。

大规模、内存敏感: - IVF_FLAT、IVF_PQ 或磁盘型索引。

关键词强的知识库: - 向量索引 + BM25 hybrid search。

强权限、多租户: - 支持 metadata filter 的向量数据库,或按租户分索引。

索引选择没有绝对最优,必须通过真实 query 和评估集测试。

20. 常见故障排查

召回差: - embedding 模型不适配。

  • 相似度指标选错。

  • 向量未归一化。

  • IVF nprobe 太小。

  • HNSW efSearch 太小。

  • chunking 不合理。

  • filter 过严。

延迟高: - top-k 太大。

  • nprobe/efSearch 太大。

  • list 分布不均。

  • 过滤下推效率差。

  • 磁盘 IO 或网络瓶颈。

内存高: - 向量维度大。

  • HNSW M 太大。

  • 保存多个副本。

  • 没有量化或压缩。

21. 核心总结

向量索引的核心是 recall、latency、memory 的权衡。 - Flat 精确但慢,是评估基线。

  • IVF_FLAT 用聚类倒排减少扫描范围,核心参数是 nlist 和 nprobe。

  • HNSW 用多层近邻图快速搜索,核心参数是 M、efConstruction、efSearch。

  • RAG 中优先保证证据召回,再优化延迟和成本。

  • 指标、归一化、过滤、更新和权限是生产系统必须关注的细节。

22. 参考资料

  • FAISS documentation: https://faiss.ai/

  • FAISS wiki: https://github.com/facebookresearch/faiss/wiki

  • Milvus IVF_FLAT documentation: https://milvus.io/docs/ivf-flat.md

  • Milvus HNSW documentation: https://milvus.io/docs/hnsw.md

  • HNSW paper: https://arxiv.org/abs/1603.09320

  • 图解向量索引: https://blog.csdn.net/wireless_com/article/details/143160133

  • FAISS 三种向量检索方式学习: https://www.cnblogs.com/zhangkele/p/18706932

            预览时标签不可点
    

    <div class="