Elasticsearch 从零到精通验收清单
这页用来回答:ES 文档是不是只讲了“倒排索引、分词、近实时”几个词,还是能让零基础真正理解搜索系统怎么设计、怎么同步、怎么排查?
学完 Elasticsearch 不能只会说“ES 查询快”。你要能解释为什么快、为什么近实时、为什么写入成功后搜不到、为什么 Mapping 改错要重建、为什么深分页慢、为什么 MySQL 和 ES 会不一致、ES 更新失败后怎么补偿。
最终目标
学完 ES 专栏后,你至少要能做到:
- 判断一个业务查询是否适合 ES,而不是所有查询都丢给 ES。
- 根据搜索页面设计文档模型和 Mapping,而不是照搬数据库表。
- 解释倒排索引、分词、term dictionary、posting list、BM25 的作用。
- 解释写入、refresh、segment、translog、flush、merge 的全过程。
- 解释 Query Phase、Fetch Phase、分片并行、协调节点合并 TopN。
- 解释
text、keyword、term、match、must、filter的区别。 - 设计 MySQL 到 ES 的同步链路,处理重复、乱序、失败、补偿和重建。
- 排查搜不到、搜不准、查询慢、写入慢、yellow/red、磁盘水位和 JVM 压力。
- 用别名完成不停机重建索引。
- 面试时标准回答在面试页,追问原理能跳回知识点页展开。
总路线
flowchart TD
A["阶段 1<br/>ES 定位和适用场景"] --> B["阶段 2<br/>文档模型和 Mapping"]
B --> C["阶段 3<br/>倒排索引和分词"]
C --> D["阶段 4<br/>写入、Refresh、Segment"]
D --> E["阶段 5<br/>查询 Query / Fetch"]
E --> F["阶段 6<br/>集群、分片、副本"]
F --> G["阶段 7<br/>MySQL 同步和一致性"]
G --> H["阶段 8<br/>性能优化和排查"]
H --> I["阶段 9<br/>商业场景和面试"]为什么要这样学?
| 阶段 | 原因 | 如果跳过 |
|---|---|---|
| 先学定位 | ES 是搜索视图,不是事务主库 | 拿 ES 做库存、支付判断 |
| 再学文档 | ES 按文档检索,不擅长临时 Join | 索引照搬数据库表,查询复杂又慢 |
| 再学倒排 | 查询快的核心在倒排索引 | 只会说“ES 快” |
| 再学写入 | 近实时、更新成本、refresh 都在这里 | 写入成功搜不到不会解释 |
| 再学查询 | 慢查询、深分页、聚合都在查询链路里 | 查询慢只会加机器 |
| 再学集群 | 生产一定涉及分片副本和健康状态 | yellow/red、未分配分片不会处理 |
| 再学同步 | ES 常和 MySQL 搭配 | 数据不一致、更新失败没补偿 |
| 最后排查 | 生产问题是多机制叠加 | 搜不到、搜不准、慢查询无证据链 |
阶段 1:ES 定位和适用场景
ES 是搜索和分析引擎,通常保存面向搜索的冗余视图。
flowchart TD
A["业务数据"] --> B["MySQL / PostgreSQL<br/>事实源"]
B --> C["消息 / CDC / 任务同步"]
C --> D["Elasticsearch<br/>搜索视图"]
D --> E["全文检索、筛选、排序、聚合、高亮"]适合
| 场景 | 为什么适合 |
|---|---|
| 商品搜索 | 全文检索、筛选、排序、聚合、高亮 |
| 订单后台检索 | 多条件、时间范围、手机号、商品名 |
| 工单搜索 | 标题、描述、处理人、状态、SLA |
| 日志分析 | 时间范围、traceId、错误码、耗时聚合 |
| 搜索建议 | 前缀召回、热度排序 |
| 医疗资产检索 | 字段名、表名、标签、批次、机构检索 |
不适合
| 不适合 | 原因 | 替代 |
|---|---|---|
| 支付主库 | 缺少关系库强事务 | MySQL / PostgreSQL |
| 强一致库存判断 | ES 近实时,可能旧值 | 库存服务 + 数据库事务 |
| 高频单字段更新 | 更新本质是删除旧文档再写新文档 | 主库保存事实,ES 异步同步 |
| 临时多表 Join | ES 文档模型不擅长运行时 Join | 写入前冗余,或数据库查询 |
| 小数据简单条件查询 | 引入 ES 成本高 | 数据库索引即可 |
验收问题:
- 为什么 ES 不能替代 MySQL?
- 为什么详情页关键状态通常要回源主库?
- 为什么 ES 适合搜索,不适合强一致交易?
阶段 2:文档模型和 Mapping
ES 不是把数据库每张表建成一个索引,而是按搜索页面设计文档。
flowchart TD
A["搜索页面需要展示和筛选什么"] --> B["确定搜索文档字段"]
B --> C["冗余品牌、类目、标签、状态"]
C --> D["设计 Mapping"]
D --> E["按字段用途选择 text / keyword / date / number"]商品搜索文档 Demo
PUT /product_search_v1
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "1s"
},
"mappings": {
"dynamic": "strict",
"properties": {
"id": { "type": "long" },
"productName": {
"type": "text",
"analyzer": "standard",
"fields": {
"keyword": { "type": "keyword", "ignore_above": 256 }
}
},
"brandName": { "type": "keyword" },
"categoryName": { "type": "keyword" },
"tags": { "type": "keyword" },
"price": { "type": "scaled_float", "scaling_factor": 100 },
"stockStatus": { "type": "keyword" },
"saleCount": { "type": "long" },
"updatedAt": { "type": "date" }
}
}
}字段类型验收
| 字段用途 | 推荐类型 | 原因 |
|---|---|---|
| 全文检索 | text | 会分词,用于 match 查询 |
| 精确过滤 | keyword | 不分词,用于 term/filter |
| 排序聚合 | keyword、数值、日期 | 有 doc values |
| 金额 | scaled_float 或 long 分 | 避免浮点误差 |
| 时间 | date | 范围查询和排序 |
| 描述大字段 | 可关闭部分索引或只用于展示 | 避免索引膨胀 |
验收问题:
text和keyword区别是什么?- 为什么 Mapping 改错通常要重建索引?
- 为什么生产建议显式 Mapping 和
dynamic: strict? - 为什么聚合排序字段不要直接用
text?
阶段 3:倒排索引和分词
倒排索引是“词 -> 文档”的映射。
flowchart TD
A["文档:无线蓝牙降噪耳机"] --> B["Analyzer 分词"]
B --> C["无线"]
B --> D["蓝牙"]
B --> E["降噪"]
B --> F["耳机"]
C --> G["Posting List: doc1, doc8"]
D --> H["Posting List: doc1, doc3"]
E --> I["Posting List: doc1, doc9"]查询时不再逐行扫描商品名,而是按词找到候选文档,再合并、评分、排序。
为什么 ES 查询快
| 机制 | 作用 |
|---|---|
| term dictionary | 快速定位词 |
| posting list | 找到包含该词的文档 |
| skip list / bitset | 加速跳跃和过滤 |
| BM25 | 根据词频、逆文档频率、字段长度评分 |
| doc values | 支撑排序和聚合 |
| 分片并行 | 多个分片同时查,协调节点合并 |
但 ES 不是任何查询都快。深分页、大聚合、脚本排序、前缀通配、大 _source、分片过多都可能很慢。
term 和 match
| 查询 | 是否分析查询词 | 适合 |
|---|---|---|
term | 不分析 | keyword、ID、状态、枚举 |
match | 分析 | text 全文检索 |
验收问题:
- 为什么
term查text整句话可能搜不到? - 索引分词和查询分词为什么必须配合?
- BM25 为什么会影响排序?
- 为什么同义词改动后可能要重建或重开索引?
详细看:倒排索引、分词与 BM25 评分。
阶段 4:写入、Refresh、Segment
ES 写入成功不等于立刻可搜索。
flowchart TD
A["客户端写入文档"] --> B["协调节点路由到主分片"]
B --> C["主分片写入内存 buffer"]
C --> D["写 translog"]
D --> E["复制到副本分片"]
E --> F["返回写入成功"]
C --> G["refresh 生成可搜索 segment"]
G --> H["查询可以搜到新文档"]refresh、flush、merge
| 机制 | 做什么 | 解决什么 |
|---|---|---|
| refresh | 内存 buffer 生成可搜索 segment | 让新文档能被搜索 |
| flush | Lucene commit,裁剪 translog | 崩溃恢复边界 |
| merge | 小 segment 合并成大 segment | 清理删除标记、减少查询开销 |
更新为什么成本高
Lucene segment 不可变,更新不是原地修改:
flowchart TD
A["更新文档"] --> B["旧文档打删除标记"]
B --> C["写入新版本文档"]
C --> D["refresh 后新版本可见"]
D --> E["merge 时清理旧版本"]所以高频更新字段,比如库存实时扣减,不适合把 ES 当最终判断来源。
验收问题:
- 为什么 ES 叫近实时搜索?
- 写入成功但搜不到,第一步判断什么?
- refresh_interval 调小有什么代价?
- update 为什么不是原地修改?
阶段 5:查询 Query / Fetch
ES 分布式查询通常分 Query Phase 和 Fetch Phase。
flowchart TD
A["客户端搜索请求"] --> B["协调节点"]
B --> C["分发到相关分片"]
C --> D["各分片 Query Phase<br/>召回、过滤、评分、排序 TopN"]
D --> E["协调节点合并全局 TopN"]
E --> F["Fetch Phase<br/>拉取 _source、高亮、返回字段"]
F --> G["返回结果"]Query 慢和 Fetch 慢
| 慢的位置 | 常见原因 |
|---|---|
| Query 慢 | 候选集大、wildcard、script、深分页、大聚合、分片多 |
| Fetch 慢 | _source 大、高亮重、返回字段多、inner_hits |
深分页为什么慢
from + size 很大时,每个分片都要取大量候选结果,协调节点合并后再丢弃前面的。
from = 100000
size = 20
5 个分片各自可能要准备 100020 条候选
协调节点合并后丢掉前 100000 条优化方向:
- 限制最大页数。
- 使用
search_after。 - 使用 PIT 保持分页视图。
- 改成按时间、ID、业务游标翻页。
详细看:查询 Query 与 Fetch 全过程。
阶段 6:集群、分片、副本
分片是容量和并行查询单位,副本是高可用和查询吞吐保障。
flowchart TD
A["Index"] --> B["Primary Shard 0"]
A --> C["Primary Shard 1"]
A --> D["Primary Shard 2"]
B --> E["Replica 0"]
C --> F["Replica 1"]
D --> G["Replica 2"]分片不是越多越好
| 分片过少 | 分片过多 |
|---|---|
| 单分片太大,迁移恢复慢 | 元数据、文件句柄、协调成本高 |
| 并行度不足 | 每次查询扇出过大 |
| 扩容不灵活 | 小分片太多浪费资源 |
yellow / red
| 状态 | 含义 | 处理 |
|---|---|---|
| green | 主分片和副本都正常 | 正常 |
| yellow | 主分片正常,部分副本未分配 | 查节点数、磁盘水位、分配规则 |
| red | 部分主分片不可用 | 优先恢复主分片和数据 |
详细看:集群。
阶段 7:MySQL 同步和一致性
商业系统常见架构:MySQL 是事实源,ES 是搜索视图。
flowchart TD
A["业务写 MySQL"] --> B["事务提交"]
B --> C["发送 MQ 或产生 Binlog"]
C --> D["同步服务消费事件"]
D --> E["按 ID 回查 MySQL 最新快照"]
E --> F["组装 ES 文档"]
F --> G["upsert 到 ES"]
G --> H{"是否成功"}
H -- "成功" --> I["记录同步成功"]
H -- "失败" --> J["重试、死信、补偿"]为什么消息里常只放 ID
- 消息更小。
- 避免旧消息携带旧字段覆盖新数据。
- 搜索文档可能来自多张表,消费端需要组装最新快照。
- 失败重试时仍能拿到主库最新状态。
ES 更新失败怎么办
| 失败类型 | 处理 |
|---|---|
| 网络超时 | 幂等重试,不能假定失败或成功 |
| ES 线程池拒绝 | 退避重试,降低并发 |
| 磁盘只读 | 处理磁盘水位,解除只读后重放 |
| Mapping 冲突 | 修正数据或 Mapping,必要时重建索引 |
| 文档太大 | 拆字段、清理无用字段 |
| 多次失败 | 死信、告警、人工修复、补偿扫描 |
不能因为 ES 更新失败就回滚 MySQL 主事务。主库已经成功时,应让搜索视图通过重试、死信、补偿、对账最终追上。
详细看:MySQL 与 ES 数据一致性。
阶段 8:性能优化和排查
搜不到排查
flowchart TD
A["用户搜不到"] --> B["查 MySQL 是否有数据"]
B --> C{"主库有吗"}
C -- "没有" --> D["业务数据本身不存在"]
C -- "有" --> E["按 ID 查 ES"]
E --> F{"ES 有文档吗"}
F -- "没有" --> G["查同步链路、MQ、CDC、死信"]
F -- "有" --> H["查 Mapping、分词、DSL、filter、权限"]查询慢排查
| 证据 | 看什么 |
|---|---|
| 最终 DSL | 是否有深分页、wildcard、script、大聚合 |
| slowlog | Query 慢还是 Fetch 慢 |
| profile | 慢在哪个 query、哪个分片 |
_source | 返回字段是否过大 |
| 分片数 | 是否过多、是否热点分片 |
| thread pool | search/write rejected |
| JVM | heap、GC、circuit breaker |
| 磁盘 | 水位、IO、只读块 |
搜不准排查
- 用
_analyze看索引分词和查询分词。 - 用
_explain看评分原因。 - 检查
must、should、filter是否设计合理。 - 检查字段 boost、业务排序、销量/时间权重。
- 检查同义词、停用词、品牌词、型号词。
详细看:性能优化与排查。
阶段 9:商业场景验收
商品搜索
必须做到:
- 文档按页面设计,不照搬商品表。
- 商品名
text+keyword子字段。 - 品牌、类目、状态用
keywordfilter。 - 价格、销量、更新时间用于排序和聚合。
- 下单价格和库存回源主库或商品服务校验。
订单检索
必须做到:
- 租户、用户权限、时间范围必须服务端强制 filter。
- 手机号、订单号、状态用精确查询。
- 商品名、备注可全文检索。
- 列表稳定排序,避免深分页。
- 订单详情和支付状态以主库为准。
医疗数据采集与资产平台
必须做到:
- MySQL 保存采集批次、资产、字段、血缘、治理结果。
- ES 保存面向检索的资产搜索文档。
- 文档冗余表名、字段名、中文名、标签、机构、批次、状态。
- 通过 MQ/CDC 同步,失败进死信和补偿。
- 查询侧统一加租户、机构、权限 filter。
面试闭环
| 高频问题 | 标准回答 | 深入原理 |
|---|---|---|
| ES 是什么 | ES 面试 | ES 总览 |
| ES 为什么快 | ES 面试 | 倒排索引与 BM25 |
| ES 为什么近实时 | ES 面试 | 写入 Refresh 与 Segment |
| text 和 keyword | ES 面试 | Mapping 与查询 |
| term 和 match | ES 面试 | 倒排索引与 BM25 |
| Query / Fetch | ES 面试 | 查询 Query 与 Fetch |
| MySQL 与 ES 一致性 | ES 面试 | MySQL 与 ES 一致性 |
| ES 更新失败怎么办 | ES 面试 | MySQL 与 ES 一致性 |
| 查询慢怎么排查 | ES 面试 | 性能优化与排查 |
最终验收题
| 问题 | 合格标准 |
|---|---|
| ES 能否替代 MySQL | 能说清事实源和搜索视图区别 |
| 文档模型怎么设计 | 能按搜索页面冗余字段 |
| Mapping 怎么设计 | 能区分 text、keyword、date、number |
| ES 为什么快 | 能讲 term dictionary、posting list、filter、doc values |
| 为什么近实时 | 能讲 buffer、translog、refresh、segment |
| 更新为什么成本高 | 能讲删除标记、新文档、merge |
| 深分页为什么慢 | 能讲各分片 TopN 和协调节点丢弃 |
| MySQL 如何同步 ES | 能讲 MQ/CDC、回查主库、幂等、补偿 |
| ES 更新失败怎么办 | 能讲重试、死信、告警、补偿、重建 |
| 查询慢怎么排查 | 能按 DSL、slowlog、profile、分片、JVM、磁盘排查 |
本章小结
真正学会 ES,不是会背“倒排索引”和“近实时”,而是能把搜索业务建模、Mapping、分词、倒排索引、写入 refresh、查询 query/fetch、分片副本、MySQL 同步、重建索引、性能排查串成闭环。
如果某个问题讲不清,就回到对应知识点页看流程图、Demo 和商业场景。ES 的难点不是 API,而是搜索视图设计、最终一致性和生产排查证据链。
