首页/数据/NoSQL 速查/倒排索引与检索成本
选型与架构50 条

倒排索引与检索成本

倒排索引把"词条 → 文档列表"组织成词典与倒排表:词条匹配(term/match)走索引很快,而前导通配、正则与对分析后词条的整串匹配要扫描大量词条或全部文档。

NoSQL 速查数据更新于 2026-10-13

倒排索引怎么组织数据

倒排索引把「词条 → 文档列表」组织成词典与倒排表:查询词条时直接从词典找到对应的文档集合,再按布尔逻辑合并。文本字段还会存放位置信息用于短语匹配,另有一份列式存储(doc values)用于排序与聚合。因此词条级匹配极快,而前导通配、复杂正则与对分析后整串值的匹配则要遍历大量词条甚至全部文档。

基本信息

核心结构词典(term dictionary)+ 倒排表(postings list)
辅助结构位置信息(支持短语查询)、doc values(排序聚合)、norm(长度归一化)
高效查询term、terms、前缀匹配、match_phrase、布尔组合
低效查询以通配符开头的 wildcard、复杂 regexp、对 text 字段做排序聚合
适用平台Elasticsearch、OpenSearch 及各类全文检索系统

典型使用场景

  • 关键词检索:把用户输入分词后做词条匹配,比 LIKE 更可控
  • 结构化过滤:状态、类型等枚举字段用 keyword 子字段做 term 查询
  • 短语与位置匹配:需要「词序不能颠倒」时使用带位置信息的匹配
  • 排序与聚合:基于 doc values 排序统计,避免对 text 字段直接聚合
  • 日志检索:先按时间与字段过滤收敛,再做文本匹配

示例

示例
// 词条精确匹配:走倒排索引,代价与命中文档数相关
GET /my-index/_search
{ "query": { "term": { "status.keyword": "open" } } }

// 前缀匹配:从词典定位前缀区间,效率可接受
GET /my-index/_search
{ "query": { "prefix": { "name.keyword": "prod-" } } }

// 前导通配:需要遍历大量词条,数据量大后代价不可控
GET /my-index/_search
{ "query": { "wildcard": { "name.keyword": { "value": "*-prod" } } } }

// 排序与聚合应落在 keyword 或数值字段上
get /my-index/_search
{ "size": 0, "aggs": { "by_status": { "terms": { "field": "status.keyword" } } } }

查询类型与代价

查询执行方式代价特征
term / terms词典定位后取倒排表并集与命中文档数成正比,最可控
prefix在词典上定前缀区间前缀越短、命中词条越多则越慢
match_phrase取位置信息校验词序比普通词条匹配多一层位置校验
wildcard(前导)枚举大量词条做匹配词条基数大时接近全量扫描
regexp在词典上做正则匹配提前收紧前缀可显著降低开销
对 text 排序聚合需要加载 fielddata 到堆内存易触发内存告警,应改用 keyword 子字段
优化的方向是「把过滤条件变成词条可命中的形式」:字段值规范化后再入库、把复合维度拆成独立字段、用 n-gram 或专用字段替代通配符查询。
把大文本字段设为允许 fielddata 做排序或聚合会占用大量堆内存,历史上是导致节点内存告警的常见原因,正确做法是加 keyword 子字段或改用 doc values。

易错点

  • 用 LIKE 或正则承担关键词检索:数据量上来后扫描代价无法收敛,本应交给倒排索引承担
  • 查询写法与分析器不匹配:字段做了小写转换或分词,却用原始大小写或整串值做 term 查询,命中始终为零
  • 对 text 字段直接排序聚合:触发堆内加载,轻则查询变慢,重则节点内存告警
  • 通配符查询不收敛数据范围:没有时间或枚举条件先把候选集压小,前导通配的成本会随索引增长线性上升

数据来源与参考

  • Elasticsearch Guide: Inverted index
  • Elasticsearch Guide: Wildcard query
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌