Elasticsearch 之所以能在大数据量下实现毫秒级的全文搜索,其核心秘密就在于它的底层数据结构——倒排索引(Inverted Index)。
如果你想精通 Elasticsearch,或者只是想在面试中对答如流,理解倒排索引和分词器(Analyzer)的原理是绝对的必修课。本文将用通俗易懂的语言、全新的案例和图解,带你彻底搞懂这两个核心概念。
一、 什么是倒排索引?
在传统的关系型数据库(如 MySQL)中,如果我们想在一个文本字段中搜索某个关键词,通常会使用LIKE %keyword%。这种方式需要扫描每一行记录(全表扫描),效率极低。
倒排索引的设计思路则完全不同。它不直接存储“哪个文档包含了什么内容”,而是存储“这个关键词出现在了哪些文档中”。
1.1 正排索引 vs 倒排索引
- 正排索引(Forward Index):以文档为核心。例如:文档 ID -> 文档内容。这是我们要存储原始数据的方式。
- 倒排索引(Inverted Index):以词(Term)为核心。例如:关键词 -> 包含该词的文档 ID 列表。这是我们用来搜索的方式。
我们可以用书籍来类比:
- 正排索引就像书的目录(章节 -> 页码),你知道第一章讲什么,但不知道“并发”这个词在哪几页出现。
- 倒排索引就像书尾的索引页(关键词 -> 页码列表),你可以直接找到“并发”这个词出现在第 15、28、99 页,直接翻过去即可。
1.2 核心结构图解
1.3 案例演示
假设我们有以下三条商品数据:
- Doc 1:
红富士苹果 - Doc 2:
新鲜的香蕉 - Doc 3:
苹果和香蕉
构建倒排索引后的逻辑结构如下表所示:
| Term (词项) | Posting List (文档 ID 列表) |
|---|---|
| 苹果 | [1, 3] |
| 红富士 | [1] |
| 香蕉 | [2, 3] |
| 新鲜 | [2] |
当你搜索“苹果”时,ES 直接定位到倒排索引中的“苹果”一行,立即得到文档 ID[1, 3],无需遍历所有数据。
二、 倒排索引是如何构建的?
倒排索引的构建不是一蹴而就的,它需要经过**分词(Tokenization)和归一化(Normalization)**等处理。
2.1 构建流程图
2.2 关键步骤
- 分词(Tokenization):将一段文本拆分成一个个独立的词(Term)。
- 例如:
Coding is FUN!->[Coding, is, FUN]
- 例如:
- 归一化(Normalization):将词标准化,提高搜索的容错率。
- 转小写:
FUN->fun(搜Fun也能搜到)。 - 词干提取(Stemming):
Coding->code(搜code也能搜到coding)。 - 停用词过滤:去掉
is、the、a等无实际意义的词。
- 转小写:
三、 搜索过程是怎样的?
当用户输入查询语句时,ES 内部发生了什么?
合并策略:
- 如果是
OR查询(默认):取并集[1, 2, 3]。 - 如果是
AND查询:取交集[3](只有文档 3 同时包含香蕉和苹果)。
四、 Elasticsearch 的灵魂:Analyzer(分词器)
分词器(Analyzer)是 Elasticsearch 处理文本的核心组件,它决定了你的数据如何被索引,以及用户如何能搜到它。
4.1 分词器的组成结构
一个 Analyzer 由三个核心组件按顺序组成:
- Character Filters(字符过滤):
- 在分词前对原始字符串进行“清洗”。
- 场景:去掉 HTML 标签(
<b>hello</b>->hello),将表情符号替换为文字等。
- Tokenizer(分词器):
- 按照规则切分字符串。
- 场景:按空格切分(Whitespace)、按标点切分(Standard)。
- Token Filters(词项过滤):
- 对切分后的词进行加工。
- 场景:转小写(Lowercase)、停用词移除(Stop)、同义词转换(Synonym)。
五、 常见的内置分词器实战
Elasticsearch 内置了多种分词器,适用于不同的场景。我们通过_analyzeAPI 来看看它们的效果。
5.1 Standard Analyzer(默认)
特点:按词切分,支持多语言,小写处理,过滤标点。最通用。
- 输入:“Hello, World! 2026”
- 处理:按标点和空格切分,转小写。
POST /_analyze{"analyzer":"standard","text":"Hello, World! 2026"}结果:[hello, world, 2026]
5.2 Simple Analyzer
特点:通过非字母字符切分,非字母字符会被去除(包括数字!),并转小写。
- 输入:“My email is user123@test.com”
- 处理:数字
123和符号@.都会被当做分隔符并丢弃。
POST /_analyze{"analyzer":"simple","text":"My email is user123@test.com"}结果:[my, email, is, user, test, com](注意:数字丢失了)
5.3 Whitespace Analyzer
特点:仅仅按照“空格”切分。不做小写转换,保留标点。
- 输入:“Java & Python”
- 处理:只认空格。
POST /_analyze{"analyzer":"whitespace","text":"Java & Python"}结果:[Java, &, Python](注意:& 符号保留了,大小写也保留了)
5.4 Keyword Analyzer
特点:不分词!将整个输入当作一个完整的 Term。
- 输入:“ORDER-2026-X”
- 适用场景:ID、枚举值、邮编、邮箱等精确匹配字段。
POST /_analyze{"analyzer":"keyword","text":"ORDER-2026-X"}结果:[ORDER-2026-X]
5.5 Stop Analyzer
特点:在 Simple Analyzer 的基础上,增加了停用词过滤(移除 the, a, is 等)。
- 输入:“The quick brown fox”
- 处理:“The” 是停用词,被移除。
POST /_analyze{"analyzer":"stop","text":"The quick brown fox"}结果:[quick, brown, fox]
六、 总结
- 倒排索引是 ES 高性能搜索的基石,它通过建立“词 -> 文档”的映射,避免了全表扫描。
- **分词器(Analyzer)**负责将文本转化为倒排索引所需的 Term。
- 选择合适的分词器至关重要:
- 搜全文内容(文章、评论):用
Standard或中文分词器(如ik_max_word)。 - 搜确切 ID、状态码:用
Keyword。 - 特殊格式文本:可能需要自定义分词器(组合 Char Filter + Tokenizer + Token Filter)。
- 搜全文内容(文章、评论):用
希望这篇文章能帮你彻底理解 Elasticsearch 的底层检索机制!