ES数据写入到查询
在分布式搜索引擎领域,Elasticsearch(简称ES)以其近实时性、高吞吐量和分布式特性脱颖而出。
# 一、数据写入:多阶段协同的可靠性保障
ES的写入并非简单的"存盘"操作,而是一套包含校验、路由、缓冲、索引及持久化的复杂流程。其核心目标是:在保证高写入性能的同时,确保数据不丢失且最终可查询。
# 1. 文档校验:数据入口的第一道关卡
客户端发送的数据需先封装为JSON文档,并指定目标索引。ES接收请求后,首先执行文档校验,确保数据符合索引的映射规则(Mapping)。
- 映射规则校验:索引的Mapping定义了字段类型(如
price为double)、分词器(如name使用ik_max_word)等规则。若文档字段与Mapping冲突(例如price传入字符串"2aasfsa"),ES会直接返回错误。
// 错误示例:price字段类型不匹配
POST /goods/_doc/3
{
"name": "iphone13",
"price": "2aasfsa" // 错误:Mapping中price为double,此处为字符串
}
// 响应:400 Bad Request,提示类型不匹配
2
3
4
5
6
7
- 动态映射(Dynamic Mapping):若文档包含Mapping中未定义的字段(如新增
type: "phone"),ES会自动推断字段类型并添加到Mapping中(可通过dynamic参数控制此行为,如strict模式禁止动态添加)。
// 动态映射示例:自动添加type字段
POST /goods/_doc/2
{
"name": "iphone13",
"price": 22,
"type": "phone" // Mapping中未定义,自动推断为text类型
}
2
3
4
5
6
7
# 2. 分片路由:确定数据的"归宿"
ES是分布式架构,一个索引由多个主分片(Primary Shard)和副本分片(Replica Shard)组成。文档必须明确写入哪个主分片,这一过程通过路由算法实现:
shard = hash(routing) % number_of_primary_shards
- 路由键(routing):默认使用文档ID(
_id),也可手动指定(如按用户ID路由,确保同一用户数据落在同一分片,优化关联查询)。 - 主分片数量(number_of_primary_shards):索引创建时指定,后续不可修改(需重建索引调整)。
示例:若goods索引有3个主分片,文档ID=1的hash(_id)=3,则3%3=0,文档将写入0号主分片。
# 3. 写入缓冲区与Translog:临时存储与可靠性保障
文档路由到目标主分片后,不会直接写入磁盘,而是先进入内存缓冲区(In-Memory Buffer),同时一条操作记录会被写入Translog(事务日志)。
- 内存缓冲区:临时存储待索引文档,减少磁盘IO频率,提升写入速度。此时文档处于"不可查询"状态。
- Translog:记录所有未持久化到磁盘的操作,是数据可靠性的核心保障。Translog默认实时刷写到磁盘(通过
index.translog.durability控制,request模式确保请求返回前刷盘),即使节点宕机,重启后可通过Translog恢复缓冲区数据,避免丢失。
# 4. Refresh:让数据"可查询"
ES通过Refresh操作将内存缓冲区的数据转换为可查询状态,默认每1秒自动执行一次(可通过index.refresh_interval配置,如-1禁用自动刷新,适合批量写入场景)。
- 过程:内存缓冲区的数据被写入Lucene分段(Segment) 并生成倒排索引(关键词到文档ID的映射,如
iphone -> [2, 3, 12]),随后内存缓冲区清空。 - 特性:分段生成后文档即可被查询(近实时性的核心),但此时分段仍存储在内存中,未持久化到磁盘。
# 5. Flush:数据永久化到磁盘
当Translog达到一定大小(默认512MB,可通过index.translog.flush_threshold_size调整)或间隔30分钟(可配置),ES会执行Flush操作,将内存中的分段永久写入磁盘:
- 内存中的分段被刷写到磁盘(通过
fsync确保物理写入)。 - 清空Translog(已持久化的数据无需再记录)。
Flush操作可手动触发(POST /索引名/_flush),但频繁触发会影响性能,建议依赖自动机制。
# 6. 副本同步:数据冗余与高可用
主分片完成写入后,会将文档同步到其对应的副本分片(Replica Shard)。只有当主分片和所有副本分片都确认写入完成后,ES才会向客户端返回"成功"响应(可通过wait_for_active_shards控制等待的副本数量)。
- 副本分片的作用:提供数据冗余(主分片故障时可升级为新主分片)、分担查询压力(查询请求可路由到副本)。
# 二、数据查询:快速定位目标文档的流程
ES的查询核心是从海量文档中快速匹配目标,流程可分为请求分发、分片内匹配、结果聚合三个阶段。
# 1. 请求分发:协调节点的"调度中心"角色
客户端的查询请求首先由协调节点(Coordinating Node) 接收,其核心任务是协调查询流程:
- 解析查询语句(如
name: iphone),确定目标索引。 - 根据索引的分片分布(主分片+副本分片),选择参与查询的分片(默认采用轮询机制在主/副本间负载均衡)。
- 将查询请求分发到选定的分片。
# 2. 分片内匹配:倒排索引的高效检索
被选中的分片接收到请求后,执行分片内查询:
- 将ES查询语句转换为Lucene可执行的查询(如
TermQuery)。 - 遍历分片内的所有Lucene分段,利用倒排索引快速匹配包含目标关键词的文档ID。
- 对匹配的文档进行相关性评分(基于TF/IDF、字段权重等算法),按评分排序后,返回前N条文档的ID和评分(不返回完整文档,减少数据传输量)。
# 3. 结果聚合:协调节点的"整合工作"
协调节点收集所有分片返回的(文档ID+评分)后,执行最终处理:
- 对所有文档ID按评分重新排序,筛选出全局前N条(如分页查询中的
from和size参数)。 - 向对应的分片请求这些文档的完整数据(通过文档ID精准获取)。
- 将完整文档整理为JSON格式,返回给客户端。
# 三、总结:近实时与高可用的设计本质
ES的写入与查询流程深刻体现了其设计哲学:
- 近实时性:通过Refresh机制(1秒间隔)平衡写入性能与查询延迟,数据并非实时可见,但延迟可控。
- 可靠性:Translog确保数据不丢失,副本分片提供冗余,Flush保障数据永久化。
- 分布式效率:分片路由实现数据均匀分布,查询时分片并行处理+协调节点聚合,支撑海量数据的高效检索。