type
status
date
slug
summary
tags
category
password
1、文档(Document)简介
Elasticsearch 中的文档(Document)是存储在索引中的基本数据单元,可以理解为是 Elasticsearch 中最小的数据实体。文档类似数据库的一条数据记录。文档以 JSON 格式表示,被索引后可以被搜索、查询和分析,每个文档都有一个唯一的 ID。
一个典型的文档可能如下所示:
文档的特性:
- 不可变性:文档一旦被索引就是不可变的,更新操作实际上是删除旧文档并创建新文档。
- 文档 ID:每个文档都有一个唯一 ID,用于标识和操作该文档。你可以自行指定,也可以让 Elasticsearch 自动生成。
_source
字段:在创建或更新文档时,原始的 JSON 数据默认会存储在_source
字段中。查询时返回的完整文档数据就来自这里。是否存储_source
会影响磁盘空间和使用方式。
- 版本控制:Elasticsearch 为每个文档维护一个版本号。每次更改(创建、更新、删除)文档,版本号都会递增。支持乐观并发控制。
2、文档的处理过程
文档的操作 API 可以参考 Elasticsearch系列:REST API
2.1 新增(索引)文档的流程
当我们执行下面语句新增文档的时候,就会执行文档的索引流程。新增(索引)文档有两种方式:
Elasticsearch 的索引文档过程涉及从文档进入系统到最终被索引和搜索的全过程
第一阶段:文档写入(Write)阶段。包含以下处理阶段:
- 客户端请求:客户端通过 REST API 发送文档(PUT/POST), 该请求可以发送到集群中的任意节点 Node,此时 Node 节点就是协调节点(Coordinating Node)。协调节点是 Elasticsearch 集群中的一种特殊节点角色,负责处理客户端请求并将这些请求路由到正确的数据节点,协调节点本身不执行文本分析、索引或搜索等实际计算。默认情况下,所有节点都具备协调功能。
- 路由确定和确定目标分片:协调节点根据文档的
_id
(如果请求中没有提供_id
,Elasticsearch 会自动生成一个) 确定目标分片,计算公式为shard_num = hash(routing) % num_primary_shards
,routing 默认是_id
。这里用到的是主分片数量,这就是为什么一旦索引创建后,主分片的数量就不能更改的原因,否则会导致路由计算全部错误,数据就找不到了。
- 路由到主分片所在节点:协调节点根据路由计算的结果,将请求转发到承载该主分片(Primary Shard)的节点,由该节点执行预处理、文本分析和索引等操作。
- 主分片处理:主分片将数据写入到事务日志(Translog) 和内存缓冲区(In-memory Buffer)。此时,这个新索引的文档还不能被搜索到,因为它还在内存缓冲区中,还没有生成到可搜索的段(Segment)中。主分片的具体操作过程如下:
- 预处理阶段
- 文档验证:检查 JSON 格式和字段类型
- 动态映射:如果索引不存在或字段未定义,自动创建映射
- 字段提取:解析文档中的各个字段
- 分析阶段(文本字段)
- 字符过滤器:处理原始文本(如去除HTML标签)
- 分词器:将文本拆分为词条(tokens)
- Token过滤器:对词条进行处理(小写化、同义词、停用词等)
- 索引阶段
- 倒排索引构建:创建 term → document 的映射
- 正排索引构建:存储原始字段值用于聚合和高亮
- Doc Values生成:列式存储用于排序和聚合
- 存储原始文档:可选地存储整个原始文档
- 副本分片同步:主分片处理完成后,会并行地将请求转发到其所有副本分片。副本分片会执行和主分片完全一样的处理流程:写入 Translog + 内存缓冲区。每个副本分片完成操作后,会向主分片报告成功或失败。
- 主分片响应协调节点 :主分片等待足够数量的分片(包括主分片和副本分片,由
wait_for_active_shards
参数控制,默认为所有分片)响应成功,或者达到了配置的超时时间,会向最开始的协调节点发送一个成功响应。
- 协调节点响应客户端:最后,协调节点将成功响应返回给客户端。此时,客户端会收到一个确认,表示文档已经被成功索引(状态码 201)。
第二阶段:Refresh 阶段。在上面第 4 步完成后,文档虽然已经写入成功(写入了 Translog),但还不能被搜索到。为了使新索引的文档对搜索可见,需要进行 Refresh 操作(默认每 1 秒执行一次),将内存缓冲区中的内容写入到文件系统缓存(Filesystem Cache)中新创建的一个不可变的 Lucene 段(Segment),并清空内存缓冲区的内容。此时,文档就变得可被搜索了。
第三阶段:Flush 阶段。为了保证数据不会丢失,Elasticsearch 会定时将文件系统缓存中的段(Segment)持久化到磁盘,并清理事务日志(Translog)。到这一步,文档已经永久持久化了。

2.2 查找文档的流程
查找文档是指使用文档 ID 查找文档的过程,例如
查找文档的过程有点类似于索引文档的过程,因为有 routing 键,可以计算出数据所在的分片。

- Client 将请求发送到任意节点 node,此时 node 节点就是协调节点(coordinating node)。
- 协调节点根据以下计算公式获取目标分片:
shard_num = hash(routing) % num_primary_shards
,routing 默认是文档的 id。
- 得到的目标分片是 primary shard,使用随机轮询算法,在 primary shard 和 replica shard 之间随机选择一个。
- 从选择的 shard 上获取文档,并把文档返回给协调节点。
- 协调节点向 Client 返回文档数据。
2.3 检索文档的流程
检索文档和查找文档的过程是不同的。
- 查找数据是已知文档 ID,我们可以根据文档 id 直接查找文档内容。
- 检索数据是根据某些关键字来检索,所以需要增加一个查找文档 id 的过程。
检索文档一般使用以下语句:

检索文档的过程分为两个阶段(Query Then Fetch):
- 查询阶段(Query Phase),目标是查询匹配的文档 ID。
- Client 将请求发送到任意节点 node,此时 node 节点就是协调节点(coordinating node)。
- 协调节点解析查询请求(包括分词、过滤、排序、分页等),将查询转换为 Lucene 查询语法。
- 协调节点将解析后的查询请求广播到索引的所有 shard,每个 shard 使用轮询算法(默认采用随机策略)在 primary shard 和 replica shard 选择一个。
- 每个 shard 在本地执行以下查询,将满足条件的数据(文档 ID、排序字段等)信息返回给协调节点。
- 使用倒排索引查找匹配的文档。如果对于关键词查询(如
"apple"
),会直接去倒排索引中查找该词项(Term),得到包含该词项的所有文档 ID 的列表(Postings List);对于复杂查询(如布尔查询、范围查询),会组合多个词项的结果。 - 计算文档的相关性评分
_score
(使用TF/IDF或BM25算法) - 应用过滤条件、排序等
- 返回 Top N 结果。每个分片会返回 Top N(根据
from + size
参数决定)个文档的 ID 和评分给协调节点。分片内部会维护一个大小为from + size
的本地优先级队列,只保留最相关的文档。
- 取回阶段(Fetch Phase),查找完整的文档数据。如果查询要求返回完整的文档内容(
_source
字段),协调节点会查询文档 ID 对应的完整文档,这一阶段类似于文档的查找过程。 - 协调节点重新进行排序,截取数据后,获取到真正需要返回的文档 ID。
- 根据文档 ID 再次请求对应的 shard,获取文档返回协调节点。
- 协调节点向 Client 返回数据。
2.4 更新/删除文档的流程
Elasticsearch 中的文档是无法直接更新的。我们通常说的对 Elasticsearch 中的文档进行更新,实际上是对指定的文档进行重新索引,也就是将原有的文档进行标记删除,然后再重新索引一个新的文档。
例如 id 为 1 的文档已经存在,我们仍然可以执行下面的更新语句
删除文档的过程:磁盘上的每个段都有一个相应的
.del
文件。当删除请求发送后,文档并没有真的被删除,而是在 .del
文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在 .del
文件中被标记为删除的文档将不会被写入新段。更新文档的过程:在新的文档被创建时,Elasticsearch 会为该文档指定一个版本号,当执行更新时,旧版本的文档在
.del
文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。3、近实时搜索机制
Elasticsearch 的近实时搜索(Near real-time search)是指向 Elasticsearch 插入文档后,不会立刻被搜索到,而是要在一段非常短的时间延迟(通常是 1s )后才能搜索到插入的文档。
Elasticsearch 不像关系型数据库一样,通过事务和隔离性来控制数据的可见,执行数据插入以后立刻就能搜索到刚刚插入的数据。Elasticsearch 主要用于大数据量和复杂场景的检索或聚合能力,近实时是为了在吞吐量、性能和数据安全性之间取得平衡而采用的设计。官方文档参考:
ElasticNear real-time search | Elasticsearch Guide [8.15] | Elastic![Near real-time search | Elasticsearch Guide [8.15] | Elastic](https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt280217a63b82a734/6202d3378b1f312528798412/elastic-logo.svg)

Near real-time search | Elasticsearch Guide [8.15] | Elastic
When a document is stored in Elasticsearch, it is indexed and fully searchable in near real-time--within 1 second. What defines near real-time search?
3.1 近实时的工作原理
在这里先介绍下:近实时搜索机制的几个重要概念:
- Memory Buffer:内存缓冲区,Elasticsearch 每当有新写入数据,都将数据写入 Memory Buffer,在 Memory Buffer 中的数据既不能被搜索,也没有被持久化。
- Filesystem Cache:Elasticsearch 定时(默认 1s)将 Memory Buffer 中的数据写入一个新的 segment 文件中,并进入操作系统缓存 Filesystem Cache,同时清空 Memory Buffer。在 Filesystem Cache 中的数据可以被搜索到,但是还没有进行持久化。所以 Elasticsearch 的新增数据的搜索并不是实时的,而是近实时搜索。
- Translog:由于 Memory Buffer 和 Filesystem Cache 都是基于内存,假设服务器宕机,那么数据就会丢失,所以 Elasticsearch 通过 Translog 日志文件来保证数据的可靠性。在数据写入 Memory Buffer 的同时,将数据也写入 Translog 日志文件。当机器宕机重启时,Elasticsearch 会自动读取 Translog 日志文件中的数据,恢复到 Memory Buffer 和 Filesystem Cache 中去。Translog 以追加写的方式写入,所以性能很高。默认每隔 5s fsync 到硬盘,fsync 前如果宕机了最多丢失 5s 的数据。
数据落盘完整过程是
write -> refresh -> flush -> merge
。
- write 过程:数据先写入内存缓冲区(Memory Buffer),同时写入磁盘上的事务日志(Translog),这时候数据还不能被搜索到。Translog 也是先写入 Filesystem Cache,然后默认每隔 5 秒刷一次到磁盘中,所以默认情况下,可能有 5 秒的数据会仅仅停留在 Memory Buffer 或者 Translog 文件的 Filesystem Cache 中,而不在磁盘上,如果此时机器宕机,会丢失 5 秒钟的数据。

- refresh 过程:每隔一段时间时间(由
index.refresh_interval
控制,默认1s),执行一次自动刷新(refresh)操作,将所有 Memory Buffer 的内容写入到 Filesystem Cache 的一个新的 Lucene 分段(Segment),然后清空 Memory Buffer 的内容。这个 Segment 是被打开且uncommited
状态,这时候数据可以被搜索到,但是还没有被持久化。这就是“近实时”的来源:数据在写入约 1 秒后,就从内存缓冲区转移到了文件系统缓存中的一个可搜索的分段里。它还没有被物理写入磁盘,但已经可以被搜索到了。

- flush 过程:默认经过 30min 或者 Translog 达到一定大小(受
index.translog.flush_threshold_size
控制,默认 512MB),执行一次刷盘(flush)操作,将 Segment 从 Filesystem Cache 物理写入磁盘。具体操作是:先将 Memory Buffer 中所有的数据 refresh 到 Filesystem Cache 的新的 Segment 中,然后创建一个新的 commit point(提交点),提交点的作用是将 Filesystem Cache 的所有 Segment 落盘,最后删除旧的 Translog 并创建一个新的 Translog 日志文件。此时数据已经被持久化。

- merge 过程:由于自动刷新流程每秒会创建一个新的 segment ,这样会导致短时间内的 segment 数量暴增。而 segment 数目太多会增加系统资源消耗。Elasticsearch 会在后台进行 merge 操作,小的 segment 被合并到大的 segment,然后这些大的 segment 再合并到更大的 segment。这就是段合并机制。

3.2 控制近实时行为
你可以根据具体场景手动控制刷新行为,以优化性能。
- 手动刷新。可以对某个索引手动调用
refresh
API,立即让缓冲区中的数据可搜索。这在演示或测试时有用,但不要在生产中频繁使用。
- 设置刷新间隔,太短的刷新间隔会增加性能开销。
在导入大量日志或重建索引时,通常不需要每秒都能搜索到。你可以临时关闭刷新来大幅提升写入性能。
- 禁用自动刷新。
- 批量导入完成后,再恢复。
- Author:mcbilla
- URL:http://mcbilla.com/article/a482c7e0-cd34-421e-8fa2-69e296b3adbc
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts