Elasticsearch 全文搜索的倒排索引原理

FreeGuideOnline 最新 2026-07-08

词条: "苹果" └─ 文档1: TF=1, 位置=0 └─ 文档2: TF=1, 位置=0

词条: "好吃" └─ 文档1: TF=1, 位置=2 └─ 文档3: TF=1, 位置=1


当执行短语查询 `“苹果很好吃”` 时,Elasticsearch 不仅要找到同时包含这几个词的文档,还会利用位置信息验证它们是否按正确顺序相邻,从而准确匹配。

## 倒排索引如何加速搜索

### 高效的布尔查询
搜索 `苹果 AND 香蕉` 时,引擎会从倒排索引中取出“苹果”的文档列表 `[1,2]` 和“香蕉”的文档列表 `[3]`,计算交集,虽然本例为空,若文档更大时,通过跳表、位图等结构可快速完成集合运算。

### 相关性算分基础
TF‑IDF、BM25 等算法依赖词频和文档频率。倒排索引直接记录了每个词的 TF 和在多少文档中出现(DF),无需再次解析原始文本,算分效率极高。

### 前缀搜索与模糊搜索
Elasticsearch 内部使用一种特殊的 FST(有限状态转换器)存储所有词条字典,使前缀查询(如 `app*`)或模糊查询(编辑距离)能够极快地找到所有可能的词条候选,再合并每个词条的倒排列表。

## 不可变的倒排索引与段合并

在 Elasticsearch 中,底层的 Lucene 库将倒排索引组织为**段(Segment)**。一旦新文档写入,并不会修改已有段,而是新建一个段。这种不可变性带来了:

- 天然的锁自由和并发搜索性能。
- 写操作仅需顺序写入新段,无随机I/O。

但段的数量过多会降低搜索效率(需合并多个小段的结果)。因此 Elasticsearch 会在后台自动进行**段合并**,将多个小段重写成更大的段,并物理删除标记为“已删除”的文档,保持搜索性能。

## 从理论到实践:简单示例

假设你用如下命令索引一条文档:

```json
POST /my_index/_doc
{
  "content": "Elasticsearch 倒排索引详解"
}

Elasticsearch 会对 content 字段进行分析(如使用 standard 分词器),生成倒排索引:

  • elasticsearch → [文档1]
  • 倒排索引详解(若中文分词)→ 倒排 [1], 索引 [1], 详解 [1]

之后执行搜索:

GET /my_index/_search
{
  "query": {
    "match": {
      "content": "倒排索引"
    }
  }
}