RAG 向量索引算法和向量数据库
把 Embedding 当普通字段逐条算距离,数据一上规模就退化为秒级全表扫描。这篇教程讲清 ANN 索引的三条技术路线(IVF 分桶、PQ 量化、HNSW 图导航)、HNSW 为什么快,以及主流向量库的选型与召回-延迟权衡。
它解决什么问题
RAG 在线检索要回答一个几何问题:在上百万条 768~3072 维的向量里,几十毫秒内找出离查询向量最近的 K 条。不做索引就是暴力扫描:100 万条 1024 维向量,单次查询约十亿次乘法,延迟轻松到秒级,对实时问答不可用。
ANN(Approximate Nearest Neighbor,近似最近邻)的思想是接受一个工程取舍:不保证找到数学上绝对的最近邻,而是用预先构建的索引结构跳过绝大多数不相关向量,只在一个小候选集里做精确比较——用 1%~5% 的召回损失换几个数量级的速度。向量数据库要解决的就是这个权衡的工程化:索引构建、内存占用、元数据过滤、增量更新、分布式扩展,全都得管。
核心原理
距离度量先定坐标系
相似度度量必须在建索引前定死,常见的三种:
- 余弦距离:只看方向不看长度,契合「语义方向接近」的检索目标,文本 RAG 最常用。
- 内积:向量归一化后与余弦排序等价,计算更直接。
- L2 欧氏距离:衡量绝对距离,适合模型明确按 L2 训练的场景。
一个高频踩坑点:查询运算符必须与索引的 operator class 一致。索引用 cosine 构建、查询却写 L2,引擎可能直接弃用索引,退化为全表扫描。
ANN 的三条路线
所有 ANN 索引都在做同一件事:把「全库比较」变成「小范围比较」,区别在于怎么划范围。
IVF(倒排索引):先用 K-Means 把向量空间聚成 nlist 个桶,每桶配一个倒排列表。查询时先找离查询点最近的 nprobe 个桶,只在桶内暴力比较。直觉是「先定城区,再挨家挨户」——nprobe 越大召回越高、延迟越高。
PQ(乘积量化):解决的是内存而非速度。把高维向量切成若干段,每段用一个码本 ID 近似表示,存储从上千个 float 压成几十个字节,距离计算用查表代替乘法。代价是有损:量化误差直接吃掉召回率,常与 IVF 组合成 IVF-PQ,用于亿级规模。
HNSW(图索引):把向量组织成分层图,查询时在图上导航。它是当前召回-延迟综合表现最强的主流算法,下面展开讲。
深入机制
HNSW 为什么快:小世界图导航
HNSW 的直觉可以类比「多层高速公路网」:最上层是稀疏的跨省高速,中间层是城际快速路,最底层是街区小路。跨省出行你不会在胡同里穿行,而是先上高速大跨度跳跃,接近目的地后再逐级下到小路精确定位。
机制上对应三点:
- 层次化构建:每个节点按指数衰减的概率被分配到最高层,越往上节点越少,天然形成金字塔。
- 贪心导航:查询从顶层入口点开始,每层反复跳到离查询点更近的邻居,直到本层无法更近,再下降一层。
- 由粗到精:高层负责快速逼近目标区域,底层(第 0 层包含全部节点)负责精细找出最终近邻。
小世界图的关键性质是「任意两点间存在短路径」,配合分层结构,查询复杂度近似对数级——百万级数据只需几十到几百次距离计算,这就是它快的根本原因。
三个参数控制权衡
- m:每个节点的最大连接数。图越密,导航越不容易陷入局部最优,召回越高;但内存和构建时间同步上升。
- ef_construction:构建时为每个新节点搜索邻居的范围。越大索引质量越好,构建越慢——这是离线成本。
- ef_search:查询时的候选队列大小。这是运行时旋钮,直接调节召回-延迟曲线,可以不重建索引在线调:
# pgvector 示例:会话级调整 ef_search,并用执行计划验证索引命中 |
实用调法:先固定 m 和 ef_construction 建好索引,再用标注集画 ef_search 的召回-延迟曲线,达到业务可接受召回就停——再往上只是用延迟换微小收益。
过滤条件与索引的博弈
带 WHERE 过滤的向量查询有个经典陷阱:ANN 索引通常先按距离取候选再应用过滤,过滤条件严格时 Top-K 会被过滤得所剩无几——比如要 10 条「category=Java」的相似文档,候选里只有 3 条满足条件,就只能返回 3 条。应对手段包括调大 ef_search 让更多候选进入过滤、按高频过滤条件建部分索引、或使用支持迭代扫描的版本(过滤后结果不足时继续扫索引)。生产上必须用执行计划确认过滤后仍命中索引。
工程实践
- 先压测再选型:用业务数据、真实 Top-K、真实过滤条件测 p99 延迟和召回率,公开 benchmark 只作初筛参考。
- 监控两个指标:p99 查询延迟和召回率抽样(定期用暴力扫描结果对比 ANN 结果)。索引膨胀、大量删除更新之后,这两个指标会先劣化。
- 索引重建要蓝绿:重建期间旧索引继续服务,新索引就绪后切换,避免查询中断。
- 冷热分层:热数据放 SSD 与内存,冷数据沉到对象存储按需加载。
- 混合检索预留通道:向量库若不支持 BM25,需要外挂搜索引擎做关键词召回,选型时把这条算进架构成本。
对比与权衡
索引算法对比
| 算法 | 原理 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|---|
| Flat 暴力 | 全量计算距离 | 100% 精确 | 数据一大就不可用 | 小规模、召回基准 |
| IVF | 聚类分桶 | 内存友好、构建快 | 需训练、召回略低 | 大规模、内存敏感 |
| PQ | 向量压缩编码 | 存储开销极低 | 精度损失较大 | 亿级海量数据 |
| HNSW | 分层图导航 | 低延迟、高召回 | 内存大、构建慢 | 中大规模在线检索 |
向量库选型对比
| 方案 | 定位 | 优势 | 代价 | 适合场景 |
|---|---|---|---|---|
| pgvector | PostgreSQL 扩展 | 技术栈统一、事务一致、SQL 过滤 | 与业务查询争资源、单机天花板 | 中小规模、已有 PG |
| Elasticsearch | 搜索引擎 | BM25 + 向量混合原生支持、生态成熟 | 资源消耗大、调优复杂 | 关键词检索为主的场景 |
| Qdrant | 专用向量库 | Rust 实现内存效率高、过滤能力强 | 多一套运维组件 | 中大规模、重过滤 |
| Milvus | 专用向量库 | 分布式、索引类型全、亿级规模验证 | 架构重、运维门槛高 | 大规模、高 QPS |
选型顺序:已有 PostgreSQL 且规模在百万级以内,先用 pgvector;业务强依赖关键词检索用 ES;规模或 QPS 涨到单机撑不住,再迁 Milvus/Qdrant;不想自运维就看托管服务——但索引参数、召回评测和成本控制仍然逃不掉。
面试视角
为什么 RAG 常用余弦相似度? 文本语义关心方向而非长度;向量归一化后内积与余弦排序等价,可用内积省计算。关键是查询、文档、索引三者的度量必须一致,否则索引可能不生效。
HNSW 为什么快? 分层小世界图:高层稀疏边做大跨度跳跃、快速逼近目标区域,底层密集边做精细搜索,配合贪心导航把查询复杂度压到近似对数级,百万数据只需几百次距离计算。
HNSW 的 ef_search 怎么调? 它是运行时参数,控制查询候选队列大小:调大召回升、延迟升。做法是固定构建参数,用标注评测集画召回-延迟曲线取拐点;无需重建索引,可在线实验。
IVF 和 HNSW 怎么选? 内存充足、追求低延迟高召回选 HNSW;内存紧张、规模超大、可接受召回损失选 IVF 或 IVF-PQ。IVF 要调 nlist/nprobe,数据分布明显变化时可能需要重训聚类中心。
向量从 100 万涨到 1 亿,架构怎么调? 单机 HNSW 的内存先撑不住:考虑量化(PQ)压缩内存、分片分布式(Milvus)、冷热分层;同时重建评测基线——规模变了,索引参数和召回目标都要重新校准。
小结
- ANN 的本质是用少量召回损失换数量级速度提升;没有索引的高维检索就是全表扫描。
- 三条路线各管一件事:IVF 管划分范围,PQ 管压缩内存,HNSW 管查询速度。
- HNSW 快的根源是分层小世界图导航;m、ef_construction、ef_search 分别控制图密度、构建质量和查询期权衡。
- 过滤查询要盯执行计划,先 ANN 后过滤可能让 Top-K 结果不足。
- 选型跟着现有技术栈和规模走:pgvector 起步,ES 做混合检索,Milvus/Qdrant 扛规模——压测数据比品牌重要。

