Elasticsearch
Elasticsearch 常被简称为 ES。它是构建在 Lucene 之上的分布式搜索和分析引擎,商业系统里常用于商品搜索、订单检索、工单检索、日志分析、搜索建议、聚合筛选和地理位置检索。
推荐阅读顺序:
- 核心概念
- 从零到生产级掌握
- 从零到精通验收清单
- 商业场景训练营
- 底层原理
- 写入、Refresh与Segment全过程
- 查询Query与Fetch全过程
- 倒排索引、分词与BM25评分
- Mapping与查询
- 分词
- 同步与重建索引
- MySQL与ES数据一致性
- 集群
- 性能优化与排查
- 商业搜索场景
- 面试题
ES 到底是什么
可以把 ES 理解成三层能力:
| 层次 | 负责什么 | 初学者怎么理解 |
|---|---|---|
| Lucene | 单机倒排索引、分词、评分、段文件 | 真正完成搜索的底层引擎 |
| Elasticsearch 节点 | REST API、索引管理、查询执行、集群通信 | 把 Lucene 包装成可访问的服务 |
| Elasticsearch 集群 | 节点发现、分片、副本、故障恢复、分布式查询 | 让搜索能扩容、高可用 |
flowchart TD
A["业务系统"] --> B["Elasticsearch REST API"]
B --> C["协调节点"]
C --> D["数据节点 A"]
C --> E["数据节点 B"]
C --> F["数据节点 C"]
D --> G["Lucene 分片和倒排索引"]
E --> H["Lucene 分片和倒排索引"]
F --> I["Lucene 分片和倒排索引"]所以 ES 不是“一个更快的 MySQL”,而是一个围绕倒排索引、文档模型、分布式分片和相关性排序设计的搜索系统。
ES 适合解决什么问题
| 场景 | 示例 | ES 提供的能力 |
|---|---|---|
| 商品搜索 | “无线降噪耳机 300以内” | 全文检索、过滤、排序、高亮、聚合 |
| 后台订单检索 | 状态、时间、手机号后四位、商品名 | 多条件查询、时间范围、精确过滤 |
| 工单检索 | 搜标题、描述、处理人、优先级 | 文本检索、权限过滤、按 SLA 排序 |
| 日志分析 | traceId、错误码、接口耗时 | 时间范围检索、聚合统计 |
| 搜索建议 | 输入“蓝牙”提示“蓝牙耳机” | 前缀召回、热度排序 |
| 附近门店 | 5km 内有货门店 | geo_point、距离过滤和排序 |
ES 不适合解决什么问题
| 不适合场景 | 原因 | 更合适的方案 |
|---|---|---|
| 支付、记账主库 | ES 不提供关系型数据库那种强事务模型 | MySQL、PostgreSQL |
| 强一致扣库存 | ES 是近实时搜索,不能负责库存最终判断 | 数据库事务、库存服务 |
| 复杂运行时 Join | ES 是文档模型,不擅长临时多表 Join | 数据库 Join,或写入前冗余字段 |
| 高频单文档精确更新 | 更新本质是删除旧文档再写新文档 | 主库保存事实,ES 保存搜索副本 |
| 小数据简单查询 | 引入 ES 会增加部署和同步成本 | 数据库索引即可 |
项目里最常见的架构是:MySQL 保存主数据,ES 保存搜索视图。业务写入以数据库成功为准,再通过消息、任务或 Binlog 把数据同步到 ES。
写入和搜索流程
写入流程
flowchart TD
A["商品或订单变更"] --> B["业务服务写入 MySQL"]
B --> C["发送变更消息或写入 Binlog"]
C --> D["同步服务组装搜索文档"]
D --> E["写入 Elasticsearch"]
E --> F["按 Mapping 处理字段"]
F --> G["text 字段分词"]
G --> H["建立倒排索引"]
F --> I["keyword、date、number 建精确索引"]
H --> J["refresh 后可搜索"]
I --> JES 是近实时搜索系统。文档写入成功后,不一定立刻被搜索到,通常要等 refresh。默认 refresh_interval 常见为 1s,所以业务上要接受短暂延迟。
查询流程
flowchart TD
A["用户输入关键词和筛选条件"] --> B["搜索 API 校验参数"]
B --> C["组装 Query DSL"]
C --> D["协调节点接收查询"]
D --> E["分发到相关分片"]
E --> F["每个分片本地查询和打分"]
F --> G["协调节点合并 TopN"]
G --> H["返回分页、高亮、聚合结果"]查询慢时不要只怀疑 ES “性能差”。常见原因包括:分片太多、Mapping 不合理、查询 DSL 过重、深分页、聚合范围过大、磁盘水位高、JVM GC 压力大、同步写入过猛。
核心概念速览
| 概念 | 类比 | 说明 |
|---|---|---|
| Index | 一类搜索视图 | 例如 product_search、order_search |
| Document | 一条 JSON 数据 | 一件商品、一个订单、一条日志 |
| Field | 字段 | productName、price、status |
| Mapping | 表结构加索引策略 | 字段类型、是否分词、是否可聚合 |
| Shard | 分片 | 数据水平拆分单位 |
| Replica | 副本 | 提高可用性和查询吞吐 |
| Analyzer | 分词器 | 决定文本如何拆词 |
| Query DSL | 查询语言 | 描述怎么搜、怎么过滤、怎么排序 |
知识点目录
| 页面 | 重点 |
|---|---|
| 核心概念 | 文档、字段、Mapping、倒排索引、refresh、segment |
| 从零到生产级掌握 | 搜索视图、文档模型、倒排索引、写入查询、同步一致性、生产排查课程线 |
| 从零到精通验收清单 | 用可验证任务串起定位、Mapping、倒排索引、写入查询、同步一致性、排查和面试闭环 |
| 商业场景训练营 | 商品搜索文档、Mapping、近实时、查询快、MySQL 同步、ES 更新失败补偿、重建索引和慢查询排查 |
| 底层原理 | ES 为什么快、为什么近实时、写入流程、查询流程、BM25、doc values |
| 写入、Refresh 与 Segment 全过程 | 协调节点、主分片、副本、buffer、translog、refresh、flush、merge、更新删除成本 |
| 查询 Query 与 Fetch 全过程 | Query Phase、Fetch Phase、分片 TopN、深分页、filter、排序聚合高亮成本 |
| 倒排索引、分词与 BM25 评分 | 倒排索引结构、Analyzer、text/keyword、BM25、搜不到和搜不准 |
| Mapping 与查询 | 字段类型、text/keyword、term/match、bool、分页、聚合 |
| 分词 | 中文分词、索引分词、查询分词、同义词、搜不到排查 |
| 同步与重建索引 | MySQL 到 ES 同步、MQ/CDC、幂等、乱序、补偿、别名切换 |
| MySQL 与 ES 数据一致性 | 双写风险、本地消息表、CDC、幂等、乱序、补偿、对账 |
| 集群 | 节点、分片、副本、健康状态、磁盘水位、分片规划 |
| 性能优化与排查 | 搜不到、搜不准、查询慢、写入慢、yellow/red、JVM、热点分片 |
| 商业搜索场景 | 商品、订单、工单、日志、搜索建议、地理位置和 Java Demo |
| 面试题 | 刷题复习入口,详细原理回到对应知识点页 |
快速启动 Demo
本地学习可以使用 Docker 快速启动单节点 ES。生产环境不要照搬这个配置。
docker run --name es-dev \
-p 9200:9200 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
-e "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
docker.elastic.co/elasticsearch/elasticsearch:8.15.0验证:
curl http://localhost:9200
curl http://localhost:9200/_cluster/health?pretty如果访问不到,优先检查:
- 容器是否启动成功。
- 端口
9200是否被占用。 - 本机内存是否足够。
- 是否启用了安全认证。
最小 CRUD Demo:商品索引
创建索引:
PUT /product_search_demo
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0,
"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" }
}
}
}写入文档:
PUT /product_search_demo/_doc/1001
{
"id": 1001,
"productName": "无线蓝牙降噪耳机 Pro",
"brandName": "SoundMax",
"categoryName": "耳机",
"tags": ["蓝牙耳机", "主动降噪", "官方旗舰"],
"price": 29900,
"stockStatus": "IN_STOCK",
"saleCount": 5821,
"updatedAt": "2026-07-01T10:00:00"
}查询文档:
GET /product_search_demo/_search
{
"query": {
"match": {
"productName": "无线降噪耳机"
}
}
}局部更新:
POST /product_search_demo/_update/1001
{
"doc": {
"price": 27900,
"updatedAt": "2026-07-01T12:00:00"
}
}删除文档:
DELETE /product_search_demo/_doc/1001这组命令覆盖了学习 ES 最基本的入口:建索引、写文档、查文档、局部更新、删除文档。
商业搜索索引设计思路
商品搜索索引通常包含:
| 字段 | 类型建议 | 用途 |
|---|---|---|
productName | text + keyword | 商品名全文搜索、高亮、必要时精确匹配 |
subTitle | text | 卖点辅助召回 |
brandId | long | 品牌过滤 |
brandName | keyword | 品牌聚合展示 |
categoryId | long | 类目过滤 |
tags | keyword | 标签过滤、运营加权 |
price | scaled_float | 价格范围、排序、聚合 |
stockStatus | keyword | 是否有货 |
saleCount | long | 销量排序 |
updatedAt | date | 同步排查和排序 |
不要照搬数据库表。ES 文档应该按搜索页面需要来设计,可以冗余品牌名、类目名、标签和统计字段,减少查询时再去 Join。
查询 Demo:商品搜索
GET /product_search_demo/_search
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "无线降噪耳机",
"fields": ["productName^5", "tags^2"]
}
}
],
"filter": [
{ "term": { "stockStatus": "IN_STOCK" } },
{ "range": { "price": { "gte": 10000, "lte": 30000 } } }
],
"should": [
{ "term": { "tags": { "value": "官方旗舰", "boost": 2 } } },
{ "range": { "saleCount": { "gte": 1000, "boost": 1.5 } } }
]
}
},
"sort": [
{ "_score": "desc" },
{ "saleCount": "desc" },
{ "id": "desc" }
],
"highlight": {
"fields": {
"productName": {}
}
}
}productName^5 表示商品名命中权重更高。filter 不参与相关性打分,适合库存、品牌、类目、价格等精确条件。should 不强制命中,但命中后可以提高排序。
使用注意事项
- Mapping 一旦设计不当,后期修改成本较高,通常需要重建索引。
- 数据库仍然是主数据源,Elasticsearch 是搜索副本。
- 写入链路要考虑最终一致性,例如商品改价、上下架后异步同步索引。
- 中文搜索要选择合适分词器,并测试同义词、停用词、品牌词和型号词。
- 搜索接口要限制分页深度,避免深分页拖垮集群。
- 订单、支付、库存判断不能依赖 ES 的搜索结果,必须回到主库或对应业务服务确认。
常见误区
| 误区 | 正确理解 |
|---|---|
| ES 可以替代 MySQL | ES 做搜索副本,MySQL 仍保存事实数据 |
| 写入成功就一定马上搜到 | ES 是近实时搜索,受 refresh 影响 |
| 分片越多越快 | 分片过多会增加协调和元数据成本 |
所有字段都用 text | 精确过滤、排序、聚合字段应使用 keyword、date、long 等类型 |
| 搜不到就是 ES 坏了 | 先检查同步、分词、Mapping、查询类型和过滤条件 |
| 查询慢只能加机器 | 先看 DSL、分片数量、慢日志、聚合和深分页 |
本章小结
Elasticsearch 的核心价值是:把业务数据转换成适合搜索的文档视图,通过倒排索引、分词、过滤、打分和聚合,让用户在大量数据中快速找到结果。
学习 ES 的主线不是背命令,而是理解:
- 数据为什么要同步到 ES。
- 字段为什么要这样建 Mapping。
- 查询为什么要区分全文搜索和精确过滤。
- 线上问题应该从同步、分词、Mapping、DSL、集群逐层排查。
