索引策略选择:稠密索引 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) |
| 适用场景 | 精确检索、关键词搜索 | 语义搜索、开放域问答 |
混合索引策略:取长补短的艺术
看到这里你应该明白了:没有一种索引是万能的。稠密索引语义强但可能漏掉精确关键词,稀疏索引关键词准但语义弱。倒排索引快但理解不了上下文,向量索引理解上下文但资源开销大。
那怎么办?答案是:混合起来用。
常见的混合策略
- 串行混合:先用倒排索引做粗筛,再用向量索引做精排。适合关键词能快速缩小候选集的场景。
- 并行混合:同时用倒排索引和向量索引检索,然后融合排序。适合对召回率要求高的场景。
- 级联混合:多级索引串联,每级用不同的索引策略逐步精化结果。适合超大规模检索系统。
我建议大多数团队从并行混合入手。为什么呢?因为它实现简单,效果立竿见影。你只需要:
- 建两套索引:一套 BM25 倒排索引,一套 HNSW 向量索引
- 查询时分别检索,各取 Top-K
- 用 RRF(Reciprocal Rank Fusion)或加权平均做融合排序
RRF 融合公式:
score(d) = Σ 1 / (k + rank_i(d))
其中 rank_i(d) 是文档 d 在第 i 路检索中的排名
k 是常数,通常取 60
这个公式的好处是:不需要归一化分数,直接用排名计算,简单粗暴但有效。
混合索引的架构图
下面这张图展示了我常用的混合索引架构。你可以看到,查询同时走两条路,最后在融合层汇合。
混合索引的调优要点
混合索引不是简单地把两个索引拼在一起就完事了。有几个关键点需要注意:
- 权重配比:稀疏和稠密结果的权重怎么分配?我一般从 0.5:0.5 开始,然后根据业务反馈调整。如果用户更在意精确匹配,就加大稀疏权重;如果更在意语义相关性,就加大稠密权重。
- Top-K 取值:每路检索取多少结果?取太少可能漏掉好结果,取太多融合层压力大。我建议每路取 50~200 条,融合后保留 Top-10 返回给用户。
- 延迟预算:两路检索是串行还是并行?并行能降低延迟,但需要多线程或异步框架支持。我习惯用 asyncio 或线程池并行执行两路检索。
一个小技巧:如果两路检索的分数分布差异很大(比如 BM25 分数在 0~10,向量相似度在 0~1),直接用 RRF 融合比加权平均更稳定。RRF 只看排名不看分数,避免了归一化带来的信息损失。
如何选择你的索引策略
说了这么多,到底怎么选?我总结了一个决策流程,你可以照着走一遍:
- 先看业务场景:是精确检索还是语义搜索?前者偏稀疏,后者偏稠密。
- 再看数据规模:百万级以下,HNSW 随便用;千万级以上,考虑 IVF+PQ 或分层索引。
- 再看资源约束:内存够不够?GPU 有没有?如果资源紧张,优先用倒排索引+BM25。
- 最后看延迟要求:要求 10ms 以内?那向量索引得用量化加速;100ms 以内?大多数方案都能满足。
我个人建议:除非你的场景极其简单,否则直接上混合索引。多花两天时间搭混合架构,比后面花两周时间调单一索引要划算得多。
我曾经犯过的错:在一个知识库搜索项目里,我一开始只用了稠密向量索引,觉得语义搜索高大上。结果用户反馈搜「价格」找不到「价钱」,因为编码器没学好同义词。后来加上 BM25 倒排索引做补充,召回率从 72% 提升到了 91%。混合索引不是锦上添花,是雪中送炭。