Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 13 章 Elasticsearch:搜索与索引

Elasticsearch 的价值不在于“能查文本”,而在于它把全文检索、过滤、聚合和分布式扩展组合成了一套可落地的搜索系统。面试和工程实践里,真正拉开差距的不是会不会写 Query DSL,而是能否解释清楚倒排索引、分片副本、写入刷新、相关性排序和线上治理之间的关系。

倒排索引与搜索基础

关系型数据库更擅长精确查找和事务处理,而搜索系统更擅长从大量文本中找出“最相关”的结果。支撑这一点的核心结构就是倒排索引。

倒排索引会把“词项到文档”的关系提前建好。以酒店搜索为例,文档里出现过“Jakarta”“airport”“hotel”这些词,索引中就会记录这些词分别出现在哪些文档、出现次数多少、位置在哪。查询时不再遍历全部文档,而是直接定位词项对应的 posting list,再做交并集、过滤和打分。

结构作用
Document一条被索引的业务记录
Term分词后得到的词项
Posting List某个词项命中的文档列表
SegmentLucene 的底层不可变索引段
Analyzer文本分析链路,负责分词与归一化

这种模型决定了 Elasticsearch 适合搜索、筛选、统计三类操作的组合,但不适合高频事务更新、强一致约束和复杂联表。工程上一个常见误区是把它当主数据库使用,结果在更新频繁、字段约束严格的场景里付出很高代价。

索引、分片与副本

索引可以理解成一类文档的逻辑集合,而真正承载数据的是分片。主分片负责承接写入与查询,副本分片用于容灾和读扩展。

概念作用设计关注点
Index逻辑数据集一般按业务域或生命周期拆分
Primary Shard主分片决定水平扩展上限,创建后不易直接调整
Replica Shard副本分片提升可用性和查询并发
Routing路由规则影响写入均衡、查询范围和热点风险

分片不是越多越好。分片过多会带来更多元数据、更多小段文件和更重的协调开销;分片过少则会限制并行度和扩容空间。经验上更重要的是让单分片大小、文档量、查询模式和节点资源处于平衡状态。

副本也不是单纯“多一份更安全”。副本数增加后,读吞吐和容灾能力会上升,但写入链路需要等待更多复制动作,磁盘和网络成本也会增加。面试里经常会追问“分片和副本分别解决什么问题”,要回答清楚:分片解决容量和并行,副本解决可用性和读扩展。

写入链路与查询链路

Elasticsearch 的写入不是“直接落成可查的数据结构”,而是先经过协调、路由、写入内存缓冲与 translog,再在 refresh 后对搜索可见。

一条文档写入链路通常可以拆成以下阶段:

  1. 客户端请求先到协调节点。
  2. 协调节点根据 _id 或自定义 routing 计算目标主分片。
  3. 主分片先写内存 buffer 和 translog,再并行复制给副本。
  4. 达到确认条件后向客户端返回成功。
  5. 后台 refresh 把内存中的数据转换成新的 segment,使其对搜索可见。

这也是为什么 Elasticsearch 常被称为 near real-time search。写成功不代表立刻能被检索到,中间存在一个 refresh 窗口。

查询链路同样分为两段:

  1. Query Phase:协调节点把查询分发到相关分片,各分片本地完成匹配、过滤和打分。
  2. Fetch Phase:协调节点汇总 Top N 命中文档,再向对应分片拉取 _source 等完整内容。

如果没有 routing 限定,查询通常会广播到多个分片。分片数越多,跨分片协调成本越高,因此“查询慢”不一定是单机算力不足,也可能是索引设计把简单请求放大成了全局扫描。

Mapping、分词与相关性

Mapping 决定字段如何被索引和查询,是搜索质量与资源成本的分水岭。最常见的字段选择是 textkeyword

字段类型适用场景特点
text标题、描述、评论等全文字段会分词,适合 match 查询
keywordID、状态、国家码、精确标签不分词,适合过滤、聚合、排序

一个常见实践是为同一业务字段同时保留全文与精确子字段,例如名称字段既支持中文分词搜索,也支持 .keyword 做精确匹配和聚合。

Analyzer 一般由字符过滤、Tokenizer、Token Filter 三部分组成。中文场景常见的分词策略是索引时更细、查询时稍粗,用来兼顾召回和精确度。若分词器选择不当,常见问题包括:

  • 召回过低:用户输入的词被切得太碎或根本切不出来。
  • 噪声过高:停用词、同义词配置不合理,结果相关性下降。
  • 聚合错误:把本该用 keyword 的字段误建成 text

相关性评分常以 BM25 为基础。它综合考虑词频、逆文档频率和字段长度,因此高频词、长文本和多字段查询都会影响最终排序。线上搜索体验差,往往不是“ES 算法不行”,而是字段权重、分词规则、过滤条件和业务排序混在一起没有分层治理。

深分页与性能优化

深分页是 Elasticsearch 的经典问题。from + size 在页码很深时,协调节点仍需要让各分片先取回更多候选,再做全局排序和截断,因此页数越深,CPU、内存和网络成本越高。

方案适用场景特点
from + size浅分页、后台列表简单直接,但深页成本高
Scroll批量导出、离线扫描基于快照,不适合实时翻页
search_after面向用户的连续翻页依赖稳定排序,性能更可控

除了分页,性能优化还要同时看写入、查询和索引模型三层。

写入侧重点:

  • 批量写入而不是单条刷入。
  • 控制 refresh 和副本策略,避免高峰期频繁生成小 segment。
  • 让路由更均匀,避免热点主分片。

查询侧重点:

  • 能 filter 就不要全靠 score。
  • 缩小搜索范围,例如按时间、租户、业务域切索引。
  • 对高频聚合与排序字段提前建好合适的数据类型。

索引侧重点:

  • 避免过宽 mapping 和无意义的动态字段爆炸。
  • 控制单分片大小,减少过多小分片。
  • 对冷热数据分层,降低热节点负担。

集群治理与常见问题

搜索集群的事故很多不是出在“查不出来”,而是出在治理:脑裂风险、分片失衡、写入堆积、段合并抖动、磁盘水位过高、mapping 失控。

常见问题与排查重点可以归纳如下:

问题常见原因处理方向
写入延迟升高bulk 太小、refresh 太频繁、磁盘吃紧调整批量、观察 translog 和 merge
查询抖动深分页、跨太多分片、缓存命中差收缩查询范围,优化排序和过滤
分片不均衡routing 偏斜、热点租户集中重设路由策略或拆索引
磁盘高水位副本过多、冷热分层缺失、保留周期过长清理旧索引,做 ILM 或冷热迁移
集群不稳定主节点选举异常、节点抖动、GC 压力大先稳控制面,再排查 JVM 和硬件

旧版本 Elasticsearch 里常被问到“脑裂”问题,本质是网络分区下多个节点都认为自己可以成为主节点。现代集群通过更严格的选主与法定人数机制降低了这类问题,但工程原则没有变:控制面节点要稳定,选主规则要清楚,不能把主节点和重查询节点混成一团。

日常治理最值得监控的维度包括:

  • 集群健康:节点数、主分片/副本分片分配、未分配分片。
  • 写入链路:bulk 延迟、拒绝数、translog、refresh 和 merge 时间。
  • 查询链路:QPS、P95/P99 延迟、慢查询、缓存命中率。
  • 资源层:CPU、堆内存、GC、磁盘水位、网络带宽。

本章小结

Elasticsearch 的核心不是某个 API,而是“倒排索引 + 分片副本 + 近实时刷新 + 相关性排序”这套整体模型。

可以把本章总结为四个判断:

  • 做搜索系统时,先想倒排索引和分词,而不是 SQL 心智。
  • 做集群规划时,先分清分片解决扩展,副本解决高可用。
  • 做性能优化时,先找出是写入、查询还是索引模型出了问题。
  • 做线上治理时,先稳住控制面、分片布局和磁盘水位,再谈复杂调优。

本章面试题与追问

  1. Elasticsearch 和 MySQL 在检索模型上有什么根本区别? 追问:为什么全文检索不适合用普通 B+ 树硬扛?

  2. 什么是倒排索引?它的核心结构包括哪些部分? 追问:posting list 里为什么不仅要记文档 ID,还常常要记位置和词频?

  3. 分片和副本分别解决什么问题? 追问:为什么分片数不是越多越好?

  4. Elasticsearch 的写入为什么是 near real-time,而不是绝对实时? 追问:translog、refresh、segment 各自起什么作用?

  5. 一次搜索请求大致会经过哪些阶段? 追问:为什么跨很多分片的查询更容易变慢?

  6. textkeyword 有什么区别? 追问:如果把聚合字段错误地建成 text,线上会有什么后果?

  7. Analyzer 的作用是什么? 追问:为什么搜索质量问题很多时候本质上是分词和字段设计问题?

  8. BM25 主要在衡量什么? 追问:为什么业务排序经常需要和相关性评分拆开设计?

  9. 深分页为什么慢?scrollsearch_after 分别适合什么场景? 追问:如果用户要持续翻页看搜索结果,你会优先推荐哪种方案?

  10. Elasticsearch 集群线上最常见的治理问题有哪些? 追问:如果磁盘水位持续升高且分片未分配,你会先检查什么?