type
status
date
slug
summary
tags
category
password
1、文档(Document)
1.1 文档是什么
Elasticsearch 中的文档(Document)是存储在索引中的基本数据单元,可以理解为是 Elasticsearch 中最小的数据实体。文档类似数据库的一条数据记录。文档以 JSON 格式表示,被索引后可以被搜索、查询和分析,每个文档都有一个唯一的 ID。
一个典型的文档可能如下所示:
文档的特性:
- 不可变性:文档一旦被索引就是不可变的,更新操作实际上是删除旧文档并创建新文档。
- 版本控制:每次修改文档都会增加版本号,支持乐观并发控制。
1.2 文档操作
1.2.1 创建(索引)文档
1、索引新文档(自动生成ID)
2、索引新文档(指定 ID)
1.2.2 查看文档
文档的元数据字段如下:
_index
:文档所属索引名称。
_type
:文档所属类型名。
_id
:文档的主键。在写入的时候,可以指定该文档的 ID 值,如果不指定,则系统自动生成一个唯一的 UUID 值。
_version
:文档的版本信息。Elasticsearch 通过使用 version 来保证对文档的变更能以正确的顺序执行,避免乱序造成的数据丢失。
_seq_no
:严格递增的顺序号,每个文档一个,Shard 级别严格递增,保证后写入的文档的_seq_no
大于先写入的文档的_seq_no
。
_primary_term
:和_seq_no
一样是一个整数,每当 Primary Shard 发生重新分配时,比如重启,Primary 选举等,_primary_term
会递增1
found
:如果查找了数据就返回 tue,就查不到数据,found 字段就是 false。
_source
:属性保存了文档的原始 JSON 数据。
1.2.3 更新文档
1、完全替换
2、部分更新
1.2.4 删除文档
1.2.5 批量操作
Bulk API 允许在单个请求中执行多个索引/创建/更新/删除操作,大幅提高操作效率。
2、文档的处理过程
1.1 新增(索引)文档的流程
当我们执行下面语句新增索引)文档的时候,就会执行文档的索引流程。索引文档有两种方式:
Elasticsearch 的索引文档过程涉及从文档进入系统到最终被索引和搜索的全过程,包含以下处理阶段:
- 文档接收阶段
- 客户端请求:通过 REST API 发送文档(PUT/POST)
- 协调节点:Client 将请求发送到任意节点 Node,此时 Node 节点就是协调节点(Coordinating Node)。协调节点是 Elasticsearch 集群中的一种特殊节点角色,负责处理客户端请求并将这些请求路由到正确的数据节点,协调节点本身不执行文本分析、索引或搜索等实际计算。默认情况下,所有节点都具备协调功能。
- 路由确定:协调节点根据文档 ID 或路由策略确定目标分片,计算公式为
shard_num = hash(routing) % num_primary_shards
,routing 默认是文档 ID。
- 分片处理
- 主分片写入:首先向主分片写入数据。第 1 步得到的目标分片是主分片,查找主分片所在的节点 Node,这个节点 Node 就是数据节点,由数据节点执行预处理、文本分析和索引等操作。
- 副本分片同步:主分片处理完成后,找到副本分片所在的节点 Node,异步复制到所有副本分片。
- 确认机制:向协调节点返回写入成功的响应,协调节点再向 Client 返回成功响应。根据
wait_for_active_shards
参数等待确认。
- 预处理阶段
- 文档验证:检查 JSON 格式和字段类型
- 动态映射:如果索引不存在或字段未定义,自动创建映射
- 字段提取:解析文档中的各个字段
- 分析阶段(文本字段)
- 字符过滤器:处理原始文本(如去除HTML标签)
- 分词器:将文本拆分为词条(tokens)
- Token过滤器:对词条进行处理(小写化、同义词、停用词等)
- 索引阶段
- 倒排索引构建:创建 term → document 的映射
- 正排索引构建:存储原始字段值用于聚合和高亮
- Doc Values生成:列式存储用于排序和聚合
- 存储原始文档:可选地存储整个原始文档
- 刷新与提交
- 内存缓冲区:新文档首先写入内存缓冲区(In-memory buffer)
- 刷新(Refresh):定期(默认1秒)将缓冲区内容转为可搜索的段(segment)
- 段合并:后台合并小段以提高性能
- 事务日志:写入操作同时记录到 translog 以保证持久性
- 提交(Flush):定期将内存中的段持久化到磁盘

1.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 返回文档数据。
1.3 检索文档的流程
检索文档和查找文档的过程是不同的。
- 查找数据是已知文档 ID,我们可以根据文档 id 直接查找文档内容。
- 检索数据是根据某些关键字来检索,所以需要增加一个查找文档 id 的过程。
检索文档一般使用以下语句:

检索文档的过程分为两个阶段(Query Then Fetch):
- 第一阶段,目标是查询到匹配的文档 ID。
- Client 将请求发送到任意节点 node,此时 node 节点就是协调节点(coordinating node)。
- 协调节点解析查询请求(包括分词、过滤、排序、分页等),将查询转换为 Lucene 查询语法。
- 协调节点确定需要搜索哪些 shard(根据索引和路由信息),每个 shard 使用轮询算法在 primary shard 和 replica shard 选择一个。
- 每个 shard 在本地执行以下查询,将满足条件的数据(文档 ID、排序字段等)信息返回给协调节点。
- 使用倒排索引查找匹配的文档
- 计算文档的相关性评分(使用TF/IDF或BM25算法)
- 应用过滤条件、排序等
- 返回Top N结果(基于分页参数)
- 第二阶段(可选),如果查询要求返回
_source
字段,协调节点会查询文档 ID 对应的完整文档,这一阶段类似于文档的查找过程。 - 协调节点重新进行排序,截取数据后,获取到真正需要返回的文档 ID。
- 根据文档 ID 再次请求对应的 shard,获取文档返回协调节点。
- 协调节点向 Client 返回数据。
1.4 更新/删除文档的流程
Elasticsearch 中的文档是无法直接更新的。我们通常说的对 Elasticsearch 中的文档进行更新,实际上是对指定的文档进行重新索引,也就是将原有的文档进行标记删除,然后再重新索引一个新的文档。
例如 id 为 1 的文档已经存在,我们仍然可以执行下面的更新语句
删除文档的过程:磁盘上的每个段都有一个相应的
.del
文件。当删除请求发送后,文档并没有真的被删除,而是在 .del
文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在 .del
文件中被标记为删除的文档将不会被写入新段。更新文档的过程:在新的文档被创建时,Elasticsearch 会为该文档指定一个版本号,当执行更新时,旧版本的文档在
.del
文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。3、近实时搜索机制
Elasticsearch 的近实时搜索(Near real-time search)是指向 Elasticsearch 插入文档后,默认会要等 1s 后才能搜索到插入的文档。Elasticsearch 不像关系型数据库一样,通过事务和隔离性来控制数据的可见,执行数据插入以后立刻就能搜索到刚刚插入的数据。Elasticsearch 主要用于大数据量和复杂场景的检索或聚合能力,近实时也是为了提高索引和检索的性能。官方文档参考:‣
近实时搜索机制的几个重要概念:
- 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 的数据。
3.1 近实时的工作原理
数据落盘完整过程是
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 的一个新的 segment,然后清空 Memory Buffer 的内容。这个新 segment 是 uncommited 状态,这时候数据可以被搜索到,但是还没有被持久化。

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

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

3.2 控制近实时行为
- 手动刷新
- 设置刷新间隔,太短的刷新间隔会增加性能开销。
- 禁用自动刷新,适合批量导入场景。
- 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