索引策略选择:稠密索引 vs 稀疏索引、倒排索引 vs 向量索引、混合索引策略

索引策略选对了,RAG 系统的性能就成功了一半。这话一点都不夸张。

我见过太多团队,花了大把时间调模型、调 prompt,结果瓶颈卡在索引上——召回慢、精度差、资源吃紧。说白了,索引就是检索系统的地基,地基没打好,上面盖什么都白搭。

这一章咱们就聊聊索引策略怎么选。我会把几种主流索引掰开揉碎讲清楚,再结合我踩过的坑,给你一套可落地的选型思路。

稠密索引 vs 稀疏索引:两种截然不同的世界观

先看一个最基础的问题:你的索引是稠密的,还是稀疏的?

这两个概念,其实对应着两种不同的向量表示方式。

核心区别一句话:稠密索引用低维、密集的向量表示语义;稀疏索引用高维、稀疏的向量表示关键词匹配。

稠密索引

稠密索引的每个向量维度通常在 128~1024 之间,但几乎所有维度都有非零值。它靠的是语义编码器(比如 BERT、Sentence-BERT)把文本映射到一个连续的语义空间。

我个人的习惯是:如果业务场景对语义相似度要求高,比如问答、对话、内容推荐,优先考虑稠密索引。它能捕捉到「苹果」和「水果」之间的语义关联,这是稀疏索引做不到的。

特性 稠密索引 稀疏索引
向量维度 128~1024,低维 数万~数百万,高维
非零值比例 几乎 100% 通常 < 1%
语义理解 强,支持近义词、同义句 弱,依赖精确关键词匹配
存储开销 中等(每向量几百字节) 较大(倒排表+位置信息)
检索速度 依赖 ANN 算法,通常亚毫秒 依赖倒排索引,毫秒级

稀疏索引

稀疏索引的代表是 BM25、TF-IDF 这类传统检索方法。每个文档被表示成一个超长向量,但只有少数维度有值——对应文档中出现的关键词。

嗯,这里要注意:稀疏索引在精确关键词匹配上表现极好,但对语义变化几乎无感。你搜「汽车」就找不到「轿车」,除非你手动做同义词扩展。

我在项目中遇到过这样一个场景:用户搜索「怎么退订会员」,稀疏索引死活召回不了「取消订阅」相关的文档。后来加了稠密索引做补充,问题才解决。

我的建议:不要二选一。现代 RAG 系统通常同时使用稠密和稀疏索引,然后做融合排序。这叫「混合检索」,后面会细讲。

倒排索引 vs 向量索引:两种检索范式的对决

聊完表示方式,再来看检索结构。倒排索引和向量索引,是两种完全不同的检索范式。

倒排索引

倒排索引的核心思想是:从词到文档的映射。每个词项后面挂一个文档列表,检索时直接定位到包含该词的文档。

说白了,它就是一本「词典」,告诉你每个词出现在哪些文档里。检索时查词典,然后合并文档列表,按 BM25 打分排序。

倒排索引的优势很明显:

  • 精确匹配快:毫秒级返回结果
  • 支持布尔查询:AND、OR、NOT 随意组合
  • 存储紧凑:用差值编码、变长编码压缩后,体积很小

但它的短板也很致命:对语义变化无能为力。你搜「笔记本电脑」,它不会召回「笔记本」或「laptop」,除非你做了词干化或同义词扩展。

向量索引

向量索引走的是另一条路:把文档和查询都编码成向量,然后在向量空间里找最近邻。

常用的向量索引算法包括:

  • HNSW(Hierarchical Navigable Small World):基于图结构,召回率高,但内存开销大
  • IVF(Inverted File Index):聚类+倒排,速度快,但精度略低
  • PQ(Product Quantization):对向量做乘积量化,大幅压缩存储

我个人比较偏爱 HNSW,因为它能在高召回率下保持亚毫秒级的检索速度。不过要注意,HNSW 是纯内存结构,数据量超过几千万条时,内存开销会让你肉疼。

我曾经踩过的坑:在一个千万级文档的项目里,我直接用 HNSW 建索引,结果单机 256GB 内存直接爆了。后来改用 IVF+PQ 的混合方案,内存降到了 32GB,召回率只掉了不到 2%。选索引算法一定要考虑资源约束。

对比维度 倒排索引 向量索引
检索方式 关键词精确匹配 语义近似匹配
典型算法 BM25、TF-IDF HNSW、IVF、PQ
召回质量 高精度,低召回 高召回,精度依赖编码器
延迟 毫秒级 亚毫秒~毫秒级
内存/存储 低(可磁盘化) 高(尤其 HNSW)
适用场景 精确检索、关键词搜索 语义搜索、开放域问答

混合索引策略:取长补短的艺术

看到这里你应该明白了:没有一种索引是万能的。稠密索引语义强但可能漏掉精确关键词,稀疏索引关键词准但语义弱。倒排索引快但理解不了上下文,向量索引理解上下文但资源开销大。

那怎么办?答案是:混合起来用。

常见的混合策略

  1. 串行混合:先用倒排索引做粗筛,再用向量索引做精排。适合关键词能快速缩小候选集的场景。
  2. 并行混合:同时用倒排索引和向量索引检索,然后融合排序。适合对召回率要求高的场景。
  3. 级联混合:多级索引串联,每级用不同的索引策略逐步精化结果。适合超大规模检索系统。

我建议大多数团队从并行混合入手。为什么呢?因为它实现简单,效果立竿见影。你只需要:

  • 建两套索引:一套 BM25 倒排索引,一套 HNSW 向量索引
  • 查询时分别检索,各取 Top-K
  • 用 RRF(Reciprocal Rank Fusion)或加权平均做融合排序

RRF 融合公式:

score(d) = Σ 1 / (k + rank_i(d))

其中 rank_i(d) 是文档 d 在第 i 路检索中的排名
k 是常数,通常取 60

这个公式的好处是:不需要归一化分数,直接用排名计算,简单粗暴但有效。

混合索引的架构图

下面这张图展示了我常用的混合索引架构。你可以看到,查询同时走两条路,最后在融合层汇合。

混合索引检索架构 用户查询 稀疏检索 BM25 倒排索引 稠密检索 HNSW 向量索引 Top-K 稀疏结果 Top-K 稠密结果 融合排序 RRF / 加权融合 最终检索结果 两路检索并行执行 融合后取 Top-N 返回

混合索引的调优要点

混合索引不是简单地把两个索引拼在一起就完事了。有几个关键点需要注意:

  • 权重配比:稀疏和稠密结果的权重怎么分配?我一般从 0.5:0.5 开始,然后根据业务反馈调整。如果用户更在意精确匹配,就加大稀疏权重;如果更在意语义相关性,就加大稠密权重。
  • Top-K 取值:每路检索取多少结果?取太少可能漏掉好结果,取太多融合层压力大。我建议每路取 50~200 条,融合后保留 Top-10 返回给用户。
  • 延迟预算:两路检索是串行还是并行?并行能降低延迟,但需要多线程或异步框架支持。我习惯用 asyncio 或线程池并行执行两路检索。

一个小技巧:如果两路检索的分数分布差异很大(比如 BM25 分数在 0~10,向量相似度在 0~1),直接用 RRF 融合比加权平均更稳定。RRF 只看排名不看分数,避免了归一化带来的信息损失。

如何选择你的索引策略

说了这么多,到底怎么选?我总结了一个决策流程,你可以照着走一遍:

  1. 先看业务场景:是精确检索还是语义搜索?前者偏稀疏,后者偏稠密。
  2. 再看数据规模:百万级以下,HNSW 随便用;千万级以上,考虑 IVF+PQ 或分层索引。
  3. 再看资源约束:内存够不够?GPU 有没有?如果资源紧张,优先用倒排索引+BM25。
  4. 最后看延迟要求:要求 10ms 以内?那向量索引得用量化加速;100ms 以内?大多数方案都能满足。

我个人建议:除非你的场景极其简单,否则直接上混合索引。多花两天时间搭混合架构,比后面花两周时间调单一索引要划算得多。

我曾经犯过的错:在一个知识库搜索项目里,我一开始只用了稠密向量索引,觉得语义搜索高大上。结果用户反馈搜「价格」找不到「价钱」,因为编码器没学好同义词。后来加上 BM25 倒排索引做补充,召回率从 72% 提升到了 91%。混合索引不是锦上添花,是雪中送炭。