微服务学习最终篇: Elasticsearch

微服务学习最终篇:Elasticsearch 从入门到生产实战

Elasticsearch(简称 ES)是一个高性能的分布式搜索引擎。它基于 Lucene 构建,支持分布式、可水平扩展,并提供 Restful 接口,可被任何编程语言调用。ELK 技术栈(Elasticsearch + Logstash + Kibana + Beats)已成为日志分析、实时监控领域的行业标配。

全文目录:

  1. 倒排索引 ------ ES 为什么这么快
  2. 核心概念:索引、文档、映射
  3. IK 分词器 ------ 中文搜索的救星
  4. 索引库与文档操作
  5. RestClient 系列 ------ Java 客户端怎么选
  6. 聚合分析 ------ 为什么需要数据聚合
  7. 分布式架构与集群高可用
  8. 读写流程原理
  9. 生产环境性能优化(加分项)
  10. 面试高频题汇总

一、倒排索引 ------ ES 为什么这么快

1.1 什么是倒排索引

Elasticsearch 之所以能在大数据量下实现毫秒级的全文搜索,核心秘密就在于它的底层数据结构------倒排索引(Inverted Index)

在传统关系型数据库(如 MySQL)中,搜索文本字段通常用 LIKE %keyword%,需要扫描每一行记录,效率极低。倒排索引的设计思路完全不同------它不存储"哪个文档包含了什么内容",而是存储 "这个关键词出现在了哪些文档中"

正排索引 vs 倒排索引

  • 正排索引(Forward Index) :以文档为核心,文档 ID → 文档内容。这是存储原始数据的方式。
  • 倒排索引(Inverted Index) :以词(Term)为核心,关键词 → 包含该词的文档 ID 列表。这是用来搜索的方式。

用书籍来类比:

  • 正排索引就像书的目录(章节 → 页码),你知道第一章讲什么,但不知道"并发"这个词出现在哪几页。
  • 倒排索引就像书尾的索引页(关键词 → 页码列表),你可以直接找到"并发"出现在第 15、28、99 页。

1.2 核心结构

倒排索引由两部分组成:

组成部分 说明
词项字典(Term Dictionary) 所有不重复词的有序列表
倒排列表(Posting List) 每个词对应的文档 ID 列表(还包含位置、频率等信息)

举例:假设有三条商品数据:

  • Doc 1:红富士苹果
  • Doc 2:新鲜的香蕉
  • Doc 3:苹果和香蕉

构建倒排索引后:

Term(词项) Posting List(文档 ID 列表)
苹果 1, 3
红富士 1
香蕉 2, 3
新鲜 2

当搜索"苹果"时,ES 直接定位到倒排索引中的"苹果"一行,立即得到文档 ID 1, 3,无需遍历所有数据。

1.3 倒排索引的构建流程

倒排索引的构建需要经过分词(Tokenization)归一化(Normalization) 等处理:

  1. 字符过滤:去除 HTML 标签等无关字符
  2. 分词(Tokenization) :将文本拆分为词语,如 "Hello World" → ["Hello", "World"]
  3. 归一化 :转小写(FUN → fun)、去除停用词(isthe)、词干提取(running → run

Elasticsearch 默认使用 standard 分析器,也支持自定义分析器(如 IK 中文分词器)。

1.4 Lucene 底层存储

每个 ES 分片底层对应一个 Lucene 索引实例。倒排索引在 Lucene 中由多个文件组成:

  • .tim 文件:存储词典(Term Dictionary),使用 FST 压缩存储,支持高效前缀查询
  • .doc 文件:存储 Posting List(文档 ID、词频等)
  • .pos 文件:存储词项在文档中的位置(用于短语查询)
  • .pay 文件:存储额外负载信息

二、核心概念:索引、文档、映射

2.1 索引(Index)

索引是存储相关数据的逻辑容器,类似于关系型数据库中的"数据库"或"表"。它是一组具有相似特征的文档集合。

⚠️ 注意:ES 中"索引"一词有双重含义:

  • 名词 :数据的逻辑存储单元(如 order_index
  • 动词:将文档写入 ES 的过程(如 "index a document")

ES 存储采用 JSON 格式,与 MongoDB 类似。

2.2 文档(Document)

文档是 ES 中可被索引的基本数据单元,采用 JSON 格式表示。每个文档属于一个索引,包含多个字段(Field)。

文档是无模式(schema-less) 的,但生产环境通常通过映射来定义结构以保证一致性。

2.3 映射(Mapping)------ 面试必考

映射是定义索引中文档结构的元数据,相当于数据库中的"表结构" 。它规定了每个字段的类型(如 textkeyworddate)、是否分词、是否可被搜索等属性。

🔥 面试高频题:text 和 keyword 有什么区别?

这是几乎所有 ES 面试必问的一道题。

维度 text keyword
是否分词 ✅ 是 ❌ 否
支持全文检索 match 查询 ❌ 只能 term 精确匹配
支持聚合 ❌(需开启 fielddata,易 OOM) ✅ 原生支持
支持排序 ❌(同上)
存储开销 高(倒排索引 + norms)

生产建议

  • 需要全文搜索 的字段 → text(如文章内容、商品描述)
  • 需要精确匹配、聚合、排序 的字段 → keyword(如状态、标签、用户 ID)
⚠️ 生产警告:不要依赖动态映射

ES 默认支持动态映射(Dynamic Mapping) :插入新字段时自动推断类型。

但这份"智能"会埋下隐患:

  • user_id 一开始是数字(如 "12345"),被识别为 long
  • 后来第三方传来 UUID(如 "abc-def"),直接写入失败------类型冲突!

生产环境原则:永远不要依赖自动映射,必须显式定义 Mapping

三、IK 分词器 ------ 中文搜索的救星

3.1 为什么需要 IK 分词器

ES 默认的分词器(如 Standard Analyzer)对中文支持较差,会将中文词语拆分为单个汉字(如"华为手机"拆分为"华""为""手""机"),无法满足中文全文检索需求。

IK 分词器是专门为中文设计的分词器,支持自定义词典,能准确拆分中文词语。

3.2 安装与使用

安装(版本必须与 ES 版本完全一致):

bash 复制代码
# 进入 ES 插件目录,下载对应版本的 IK 分词器
# https://github.com/medcl/elasticsearch-analysis-ik/releases
# 解压到 plugins/ik 目录,重启 ES

两种分词模式

  • ik_max_word:最大粒度分词,将文本拆分为尽可能多的词语(索引时用)
  • ik_smart:最小粒度分词,将文本拆分为最合理的词语(搜索时用)

测试分词

json 复制代码
POST /_analyze
{
  "analyzer": "ik_max_word",
  "text": "华为Mate 60 Pro手机"
}

3.3 自定义词典(生产必备)

编辑 plugins/ik/config/custom.dic 文件,添加自定义词语(如品牌名、专业术语),IK 分词器会优先识别这些词。

四、索引库与文档操作

4.1 索引库 CRUD

创建索引并定义 Mapping

json 复制代码
PUT /product_index
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "title": { "type": "text", "analyzer": "ik_max_word" },
      "brand": { "type": "keyword" },
      "price": { "type": "float" },
      "created_at": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" }
    }
  }
}

常用 Mapping 属性

  • type:字段类型(text、keyword、long、date 等)
  • analyzer:指定分词器
  • index:是否可被搜索(true/false)
  • doc_values:是否支持聚合排序(默认开启,text 类型默认关闭)

4.2 文档 CRUD

  • 新增/覆盖POST /index/_doc/idPUT /index/_doc/id
  • 查询GET /index/_doc/id
  • 更新POST /index/_update/id(局部更新)
  • 删除DELETE /index/_doc/id
  • 批量操作POST /_bulk

五、RestClient 系列 ------ Java 客户端怎么选

5.1 三个客户端的演进

客户端 状态 说明
TransportClient ❌ 已废弃 早期客户端,使用 TCP 协议
RestClient(低级) ✅ 可用 纯 HTTP 通信,无 ES API 封装
RestHighLevelClient ⚠️ 7.15 弃用,8.0 移除 基于 RestClient 封装,提供 ES API
Java API Client(新) 官方推荐 全新设计,零 Server 依赖

5.2 RestClient vs RestHighLevelClient

对比维度 RestClient(低级) RestHighLevelClient(高级)【已弃用】
封装程度 纯 HTTP 工具 完整 ES API 封装
请求方式 手动拼接 JSON、URL 链式 API,自动构建
版本要求 宽松,跨版本兼容 必须与 ES 版本一致
代码量 大,重复代码多 简洁,易维护
适用场景 特殊接口、调试 曾是 90% 业务首选

5.3 新项目怎么选?

直接使用 Elasticsearch Java API Client(官方推荐)。它:

  • 与 ES Server 代码零耦合,纯 REST 协议
  • API 更一致、更易用
  • 是未来长期维护的方向

迁移时需要重写代码(非兼容升级)。

六、聚合分析 ------ 为什么需要数据聚合

6.1 什么是聚合?

如果说查询是"找数据",那么聚合就是 "看趋势" 。聚合分析是 ES 的核心进阶功能,本质是"对检索结果或全量数据进行分组、统计、计算"。

为什么需要聚合?

  • 日志分析:统计各状态码的请求量
  • 电商报表:按品牌统计商品平均价格
  • 用户画像:按年龄段、地域分组统计

ES 的聚合基于倒排索引和 doc_values 实现,具备高并发、低延迟的特性,适合实时分析场景。

6.2 聚合的三大分类

类型 功能 类比 SQL
Metric(指标) 计算数值指标(avg、sum、min、max、cardinality) SELECT AVG(price)
Bucket(分桶) 将文档分组(按日期、城市、状态) GROUP BY city
Pipeline(管道) 对其他聚合结果进行二次计算 窗口函数或子查询

常见 Bucket 聚合terms(最常用)、rangedate_histogram

常见 Metric 聚合avgsumminmaxcardinality(去重计数)

6.3 面试必问:terms 聚合为什么是近似结果?

terms 聚合默认是近似结果,不是绝对精确。因为:

  1. 每个 shard 先取 top N
  2. 协调节点再合并各 shard 的结果

如果某个词在单个 shard 中未进入 top N,但在全局范围内应进入 top N,就会被遗漏。

解决方案 :调大 shard_size 参数(shard_size > size),牺牲性能换精度。

6.4 聚合执行流程

  1. Query 阶段:bool/filter 先筛选命中文档
  2. 每个 shard 本地执行聚合:分桶 + 计算指标
  3. 协调节点 merge:合并各 shard 的 bucket
  4. 如有 Pipeline 聚合:在协调节点对 bucket 再做一次计算

⚠️ 聚合 = CPU + 内存密集操作。shard 越多、bucket 越多,代价越高。

七、分布式架构与集群高可用

7.1 核心概念

ES 采用分布式架构,由多个 Node 组成 Cluster。每个索引被切分为多个 分片(Shard)

概念 说明
Cluster(集群) 多个节点组成的整体
Node(节点) 集群中的一个 ES 实例
Index(索引) 逻辑数据容器
Shard(分片) 索引的物理切分单元,每个分片是一个独立的 Lucene 实例
Replica(副本) 主分片的完整拷贝

7.2 节点角色

节点类型 核心职责
Master Node(主节点) 管理集群状态、索引创建/删除、分片分配
Data Node(数据节点) 存储数据分片,执行数据读写
Coordinating Node(协调节点) 接收用户请求、转发请求、汇总结果

生产最佳实践 :超过 5 节点的集群必须角色分离------候选主节点独立部署,不承担数据存储压力。

7.3 分片与副本

分片(Primary Shard)

  • 文档写入的唯一入口
  • 索引创建时指定数量,创建后不可修改(这是面试高频考点!)
  • 如需修改,只能重建索引

副本(Replica Shard)

  • 主分片的完整拷贝
  • 高可用保障:主分片故障时,副本可提升为新主分片
  • 读负载均衡:副本可承接读请求
  • 数量可动态修改
  • 必须与主分片分布在不同的节点上

7.4 高可用机制

  • Master 选举:基于 Raft 共识算法
  • 脑裂防护 :配置 minimum_master_nodes = (候选主节点数 / 2) + 1
  • 故障自愈:节点故障 → 副本升主 → 新副本补齐 → 分片重平衡
  • 快照备份:支持增量备份至 HDFS、对象存储
  • ILM 索引生命周期管理:热-温-冷-冻分层存储

八、读写流程原理

8.1 写入流程

复制代码
Client → Coordinating Node → 路由计算 → Primary Shard → 同步 Replica → 返回 ACK

详细步骤

  1. 客户端向协调节点发送写请求
  2. 协调节点对 _id 进行哈希路由,计算文档属于哪个分片
  3. 将请求转发给对应的 Primary Shard
  4. 数据先写入 memory buffer ,再写入 translog(事务日志)
  5. 并行同步到所有 Replica Shard
  6. 所有副本确认后,返回成功给客户端

为什么分片数不能改? 因为路由算法 shard = hash(_id) % number_of_shards 依赖分片数量,改了会导致数据找不到。

8.2 读取流程

复制代码
Client → Coordinating Node → 路由计算 → Primary/Replica(轮询)→ 返回文档

详细步骤

  1. 客户端向协调节点发送读请求
  2. 协调节点对 _id 进行哈希路由,确定分片位置
  3. 使用 round-robin 轮询算法 ,在 Primary 和所有 Replica 中随机选择一个
  4. 从选中的分片读取文档并返回

💡 读请求可以从 Primary 或 Replica 读取,实现读负载均衡。

九、生产环境性能优化(加分项)

9.1 分片规划黄金法则

  • 单个分片推荐大小:20GB - 50GB
  • 过大 → 故障恢复慢
  • 过小 → 分片数量过多,元数据管理压力大
  • 单个节点分片数 ≤ 磁盘容量(GB) × 20

9.2 索引优化

  • 显式定义 Mapping ,关闭动态映射(dynamic: falsestrict
  • 禁用不需要的字段"index": false"doc_values": false
  • 合理设置刷新间隔index.refresh_interval(写入密集时可调大)
  • 使用索引模板统一管理 settings 和 mappings

9.3 查询优化

  • 使用 Filter 上下文(不参与评分,可缓存)
  • 避免深度分页from + size 过大),使用 search_after 或 Scroll
  • 控制聚合的 sizeshard_size,避免高基数字段聚合
  • 合理使用 _source:只返回需要的字段

9.4 硬件与 JVM

  • filesystem cache 要留足够内存:ES 严重依赖 OS 缓存
  • JVM 堆内存不超过 32GB(压缩指针失效)
  • 堆内存留一半给 OS 缓存

十、面试高频题汇总

问题 核心考点
ES 为什么比数据库快? 倒排索引 + 内存缓存,避免全表扫描
text 和 keyword 区别? 分词 vs 不分词、聚合排序支持
主分片数量能改吗? 不能,创建后不可修改
副本数量能改吗? 能,动态修改
ES 是实时搜索吗? 准实时(NRT),refresh 后才可见
terms 聚合精确吗? 默认近似,可调大 shard_size
如何处理集群 Yellow/Red? Yellow:副本不足;Red:主分片丢失
如何避免脑裂? 配置 minimum_master_nodes
RestHighLevelClient 还能用吗? 7.15 弃用,8.0 移除,推荐 Java API Client

以上便是 Elasticsearch 从核心原理到生产实践的完整知识体系。掌握这些内容,足以应对绝大多数 ES 相关的面试与日常工作场景。

相关推荐
Elasticsearch1 小时前
教程:使用 ES|QL 进行威胁狩猎
elasticsearch
clorinda2 小时前
PyTorch 手写数字识别学习笔记
pytorch·笔记·学习
m4Rk_2 小时前
【论文阅读】Agent 记忆机制(63):SAMem——把经验记忆细化为带长期价值的状态—Thought
论文阅读·人工智能·学习·开源·github
kyrie_sakura2 小时前
MySQL数据库学习笔记1 -- 基础概念,sql语句
数据库·学习·mysql
吴声子夜歌2 小时前
Linux命令——学习Shell(三)
linux·chrome·学习
小猪佩奇TONY3 小时前
Linux 内核学习(18) --- linux dma_buf 机制
linux·运维·学习
智搜广告3 小时前
GEO优化公司怎么选?智搜广告从三个维度帮你判断
大数据·人工智能·python·elasticsearch·microsoft·geo
「、皓子~3 小时前
海狸IM 2.1 私有化部署从零到一:中间件、微服务与 Nginx 全流程
nginx·flutter·微服务·中间件·开源软件·im·海狸im
叶子野格3 小时前
《Verilog学习:数字系统设计基础》
学习·fpga开发