ES的常见操作与原理分析
集群
简述
- 是一个由多个节点组成的网络,这些节点相互连接并共享数据,使用的主从结构(Master-Slave)
- 集群中的节点可以扮演不同的角色,如:主节点、数据节点或者ingest节点
节点分析
主节点(Master Node)
- 负责集群层面的相关操作,管理集群变更
- o 主节点全局唯一,通过选举晋升为Master节点
数据节点(Data Node)
- 负责保存数据、执行数据相关操作:CRUD、搜索、聚合等
预处理节点(Ingest node)
- 预处理操作允许在索引文档之前,即写入数据之前,通过事先定义好的一系列的Processors(处理器)和pipeline(管道),对数据进行某种转换、富化
协调节点(Coordinating Node)
- 客户端请求可以发送到集群的任何节点,每个节点都知道任意文档的位置,然后转发这些请求,收集数据并返回给客户端,处理客户端请求的节点称为协调节点
部落节点(Tribe Node)
- 该功能运行部落节点在多个集群之间充当联合客户端
- 它不做主节点、也不做数据节点,仅用于路由请求,本质上是一个智能负载均衡器,从5.0版本开始,这个角色被协调节点取代
集群健康状态
- Green,所有主分片和副分片都正常运行
- Yellow,所有主分片都正常运行,存在非正常运行的副分片。这意味着存在单点故障风险
- Red,有主分片没能正常运行
集群状态
- 集群状态元数据是全局信息,元数据包括内容路由信息、配置信息等
集群扩容
- 当扩容集群、添加节点时,分片会均衡地分配到集群的各个节点,从而对索引和搜索过程进行负载均衡,这些都是系统自动完成的
- 分片副本实现了数据冗余,从而防止硬件故障导致的数据丢失
集群工作原理的关键步骤
- 节点发现,新节点加入集群或现有节点加入集群时,它们通过广播请求来发现其他节点
- 组成集群,一旦节点发现,他们将组成一个集群并开始协调工作
- 分片分配,索引创建过程中,分片被分配给集群中的节点
- 数据复制,每个分片可以有一个或多个复制,以确保数据的高可用性
- 负载均衡,当新文档被索引或旧文档被删除时,集群会自动均衡各分片的负载
- 故障转移,如果主节点或数据节点失效,其他节点会接管失效节点的工作
集群启动流程
- 选举主节点
- 选举规则与选举算法
- 收集集群元信息
- 收集各节点存储的元信息,根据版本号,确定最新的元信息,然后把这个信息广播下去
- allocation过程
- 选主分片
- 选副分片
- index recovery
- 主分片recovery
- 副分片recovery
- 集群启动日志
节点启动
流程相关工作
- 解析配置,包括配置文件和命令行参数
- 检查外部环境和内部环境,例如JVM版本、操作系统内核参数等
- 初始化内部资源,创建内部模块,初始化探测器
- 启动各个子模块和keepalive线程
流程操作
- 启动脚本
- 解析命令行参数和配置文件
- 加载安全配置
- 检查内部环境
- 检查lucene版本
- 检查jar冲突
- 检查外部环境
- 堆大小检查
- 文件描述符检查
- 内存锁定检查
- 最大线程数检查
- 最大虚拟内存检查
- 最大文件大小检查
- 虚拟内存区域最大数量检查
- JVM Client模式检查
- 串行收集检查
- 系统调用过滤器检查
- OnError与OnOutOfMemoryError检查
- Early-access检查
- G1GC检查
- 启动内部模块
- discovery.start()
- clusterService.start()
- nodeConnectionsService.start()
- 启动Keepalive线程
节点关闭
流程相关内容
- 关闭快照和HTTPServer,不再响应用户REST请求
- 关闭集群拓扑管理,不再响应Ping请求
- 关闭网络模块,让节点离线
- 执行各个插件的关闭流程
- 关闭IndicesService
关闭节点的场景
- 分片读写过程中执行关闭
- 主节点被关闭
选主流程
选举算法
- Bully算法
- Paxos算法
配置项
- discovery.zen.minimum_master_nodes
- 最小主节点数
- 用于判断的场景
- 触发选主
- 决定Master
- gateway选举元信息
- Master发布集群状态
- discovery.zen.ping.unicast.hosts
- 集群的种子节点列表
- discovery.zen.ping.unicast.hosts.resolve_timeout
- dns解析超时时间,默认5秒
选举流程分析
投票与得票的实现分析
确立Master或加入集群
节点失效检测
写入流程
简述
- 在ES中,写入单个文档的请求称为Index请求,批量写入的请求称为Bulk请求
- 写单个和多个文档使用相同的处理逻辑,请求被统一封装为BulkRequest
文档操作
操作类型(OpType)
- INDEX(0),向索引中"put"一个文档的操作称为"索引"一个文档。此处的"索引"为动词
- CREATE(1),put请求可以通过op_type参数设置操作类型为create,在这种操作下,如果文档已经存在,则请求将失败
- UPDATE(2),默认情况下,"put"一个文档时,如果文档已经存在,则更新它
- DELETE(3),删除文档
常见参数
- version,设置文档版本号,主要用于实现乐观锁
- version_type,请求参数指定的版本号于存储的文档版本号相同,则写入;默认为internal,其它可选值由external等
- op_type,可设置为create。代表仅在文档不存在时才写入。如果文档已经存在,则请求失败
- routing,指定routing可使用routing值进行路由;ES默认使用文档ID进行路由
- wait_for_active_shards,用于控制一致性,当指定数量的分片副本可用时才执行写入,否则重试直至超时;默认为1,主分片可用即执行写入
- refresh,写入完毕后执行refresh,使其对搜索可见
- timeout,请求超时时间,默认1分钟
- pipeline,指定事先创建好的pipeline名称
Index/Bulk基本流程
协调节点处理流程
- 参数检查
- 处理pipeline请求
- 数据预处理(ingest)工作通过定义pipeline和processors实现
- 如果Index或Bulk请求中指定了pipeline参数,则先使用相应的pipeline进行处理
- 如果当前节点不具备预处理资格,则将请求随机转发到其它具备资格的节点进行处理
- 自动创建索引
- 如果配置为允许自动创建索引(默认允许),则计算请求中涉及的索引,可能有多个,其中哪些索引是不存在的,然后创建它
- 对请求的预先处理
- 对请求的预先处理只是检查参数、自动生成ID、处理routing等
- 检测集群状态
- 协调节点在开始处理时会先检测集群状态,若集群异常则取消写入。例如:Master节点不存在
- 内容路由,构建基于Shard的请求
- 将用户的bulkRequest重新组织为基于shard的请求列表
- 根据路由算法计算某文档属于哪个分片
- 如果这些文档的主分片都属于同一个,则写请求被合并为1个
- 如果不同则遍历所有涉及的分片
- 路由算法
- 路由算法就是根据routing和文档id计算目标shardid的过程
- es使用随机id和hash算法来确保文档均匀地分配给分片
- 转发请求并等待响应
- 根据集群状态中的内容路由表确定主分片所在节点,转发请求并等待响应
- 待收到所有响应后(无论成功还是失败的),回复给客户端
主分片节点流程
- 检查请求
- 主分片所在节点收到协调节点发来的请求后,先做校验工作
- 主要检测要写的是否是主分片,allocationId是否符合预期,索引是否处于关闭状态
- 是否延迟执行
- 判断请求是否需要延迟执行,如果需要延迟则放入队列,否则继续下面的流程
- 判断主分片是否已经发生迁移
- 如果发生迁移,则转发请求到迁移后的节点
- 检测写一致性
- 在写之前,检测本次写操作涉及的shard,活跃shard数量是否足够,不足则不执行写入
- 默认是,只要主分片可用就执行写入
- 写Lucene和事务日志
- 遍历请求,处理动态更新字段映射,然后调用InternalEngine#index逐条对doc进行索引
- 先写入Lucene,生成Sequence Number和Version
- 后写Translog
- flush translog
- 根据配置的translog flush策略进行刷盘控制,定时或立即刷盘
- 写副分片
- 将主分片的变更信息同步至副分片,通过向目标节点发送请求,等待响应的方式,并收集响应信息
- 处理副分片写失败情况
- 主分片所在节点将发送一个shardFailed请求给Master
- 然后Master会更新集群状态,更新该节点的状态信息
副分片节点流程
- 执行与主分片基本相同的写doc过程,写完毕后回复主分片节点
写入优化
简述
- 在ES的默认设置下,是综合考虑数据可靠性、搜索实时性、写入速度等因素的
- 当离开默认设置、追求极致写入速度时,很多是以牺牲可靠性和搜索实时性为代价的
- 有时候,业务上对数据可靠性和搜索实时性要求并不高,反而对写入速度要求很高,此时可以调整一些策略,最大化写入速度
优化思路
- 加大translog flush间隔,目的是降低iops、writeblock
- 加大index refresh间隔,除了降低I/O,更重要的是降低了segment merge频率
- 调整bulk请求
- 优化磁盘间的任务均匀情况,将shard尽量均匀分布到物理主机的各个磁盘
- 优化节点间的任务分布,将任务尽量均匀地发到各节点
- 优化Lucene层建立索引的过程,目的是降低CPU占用率及I/O,例如禁用_all字段
相关配置
日志持久化
translog flush
- index.translog.durability
- request,每个请求都flush
- async,表示根据sync_interval配置的策略进行刷新
- index.translog.sysnc_interval
- 加大刷盘间隔时间。默认5s,不可低于100ms
- index.translog.flush_threshold_size
- 默认值为512MB,超过这个大小会导致refresh操作,产生新的Lucene分段
索引刷新
- index.refresh_interval
- 默认情况下索引的refresh_interval为1秒
- 这意味着数据写1秒后就可以被搜索到,每次索引的refresh会产生一个新的Lucene段,这会导致频繁的segment merge行为
- 如果不需要这么高的搜索实时性,应该降低索引refresh周期,例如设置120s
段合并
segment merge操作对系统I/O和内存占用都比较高,而merge是由Lucene控制,可以尝试动态调整合并策略的参数来修改merge过程
-
index.merge.policy.segments_per_tier
- 该属性指定了每层分段的数量,取值越小则最终segment越少,因此需要merge的操作更多,可以考虑适当增加此值,默认为10
-
index.merge.policy.max_merged_segment
- 单个segment的最大容量,默认5GB,可以考虑适当降低此值
索引缓冲区
indexing buffer在为doc建立索引时使用,当缓冲满时,会刷入磁盘,生成一个新的segment,这是refresh_interval刷新索引外,另一个生成新segment的机会;
每个shard有自己的indexing buffer
-
indices.memory.index_buffer_size
- 索引buffer的大小,默认为整个堆空间的10%
-
indices.memory.min_index_buffer_size
- 默认48MB
-
indices.memory.max_index_buffer_size
- 默认无限制
相关操作
使用bulk请求
- 简述
- 批量操作比单个操作效率高得多
- 但要注意bulk请求的整体字节数不要太大,太大的请求可能会给集群带来内存压力
- 因此每个请求最好避免超过几十兆字节,即使较大的请求看上去执行的更好
- bulk线程池和队列
- 建立索引的过程属于计算密集型任务,应该使用固定大小的线程池配置,来不及处理的任务放入队列
- 队列大小可以适当增加,但一定要严格控制大小,过大的队列导致较高的GC压力,并可能导致FGC频繁发生
- 并发执行bulk请求
磁盘间的任务均衡
-
简单轮询
- 在系统初始阶段,简单轮询的效果是最均匀的
-
基于可用空间的动态加权轮询
- 以可用空间作为权重,在磁盘之间加权轮询
节点间的任务均衡
- 通过cat接口观察bulk线程池和队列情况
- get {host}/_cat/thread_pool
索引过程中的优化思路
- 自动生成doc ID
- 调整字段Mappings
- 减少字段数量,对于不需要建立索引的字段,不写入ES
- 将不需要建立索引的字段index属性值设置为not_analyzed或no
- 对字段不分词或者不索引可以减少很多运算操作,降低CPU占用,尤其是binary类型,默认情况下占用CPU非常高,而这种类型进行分词通常没有什么意义
- 减少字段内容长度,如果原始数据的大段内容无需全部建立索引,则可以尽量减少不必要的内容
- 使用不同的分析器(analyzer),不同的分析器在索引过程中运算复杂度也有较大的差异
- 调整_source字段
- _source字段用于存储doc原始数据,对于部分不需要存储的字段,可以通过includes excludes过滤
- 或者将_source禁用,一般用于索引和数据分离
- 这样可以降低I/O的压力,不过实际场景中大多不会禁用_source
- 禁用_all字段
- ES 6.x后_all字段默认不启用
- 可以在mapping中将enabled设置为false来禁用_all字段
- 对analyzed的字段禁用norms
- norms用于在搜索时计算doc的评分,如果不需要评分,则可以将其禁用
- index_options设置
- 用于控制在建立倒排索引过程中,哪些内容会被添加到倒排索引
- 设置可以一定程度降低索引过程中的运算任务,节省CPU占用率
I/O异常处理
节点故障
可能触发关闭引擎的操作,造成节点故障
- createSearcherManager,创建搜索管理器
- index,索引文档
- delete,删除文档
- sync flush,同步刷新
- sync commit,同步提交
- flush,刷入磁盘
- force merge,手工合并Lucene分段
Engine关闭过程
- 将Lucene标记为异常
- 关闭shard,然后汇报给Master
Master的对应处理
- 收到节点的SHARD_FAILED_ACTION_NAME消息后,Master通过reroute将失败的shard通过reroute迁移到新的节点,并更新集群状态
异常处理流程
- 如果请求在协调节点的路由阶段失败,则会等待集群状态更新,拿到更新后,进行重试,如果再次失败,则仍旧等集群状态更新,直到超时1分钟为止。超时后仍失败则进行整体请求失败处理
- 在主分片写入过程中,写入是阻塞的。只有写入成功,才会发起副本请求。如果主shard写失败,则整个请求被认为处理失败。如果有部分副本写失败,则整个请求被认为处理成功
- 无论主分片还是副分片,当写一个doc失败时,集群不会重试,而是关闭本地shard,然后向Master汇报,删除是以shard为单位的
补充
- Get操作/读取Doc失败不会触发shard迁移
读取流程
简述
- ES的读取流程分为Get和Search两种操作,这两种读取操作有较大的差异
- GET/MGET必须指定三元组:_index、_type、_id。也就是根据文档id从正排索引中获取内容
- 而Search不指定_id,根据关键词从倒排索引中获取内容
- GET API默认是实时的,实时的意思是写完了可以立即读取,但仅限于GET、MGET操作,不包括搜索
- GET/MGET的实时读取依赖于从translog中读取实现(5.x版本之后改为refresh),因此系统对实时读取的支持会对写入速度有负面影响
GET操作
可选参数
- realtime,默认为true。Get api默认是实时的,不受索引刷新(refresh)频率设置的影响
- source filtering,默认情况下,返回文档的全部内容(在_source字段中)。可用设置为false,不返回文档内容;同时可用使用_source_include和_source_exclude过滤返回原始文档的部分字段
- stored Fields,对于索引映射中store设置为true,本选项用来指定返回哪些字段
- _source,只返回原始文档内容,其它的_id等元信息不返回
- routing,自定义routing
- preference,默认情况下,从分片的多个副本中随机选择一个,通过指定优先级(preference)可以选择从主分片读取,或者尝试从本地读取
- refresh,默认为false,若设置为true,则可以在读取之前先执行刷新操作,这对写入速度有负面影响
- version,如果指定了版本号,那么当文档实际版本号与请求的不符时,将返回409错误
基本流程
- 客户端发送请求
- 协调节点接收到请求,并通过请求中的参数,来确认文档所属分片
- 协调节点通过集群状态中的内容表查询分片的详细信息,分片与副本信息
- 协调节点将请求转发到任意副本节点进行处理请求
- 副本节点接收到请求,进行索引文档,并将结果返回给协调节点
- 协调节点获取返回的结果,并将该结果返回给客户端
详细分析
- 协调节点
- 内容路由
- 在构造函数中,准备集群状态、节点列表信息
- 根据内容路由算法计算目标shardid,也就是文档应该落在哪个分片上
- 计算出目标shardid后,结合请求参数中指定的优先级和集群状态确定目标节点,由于分片可能存在多个副本,因此计算出的是一个列表
- 转发请求
- 作为协调节点,向目标节点转发请求,或者目标是本地节点,直接读取数据
- 内容路由
- 数据节点
- 读取及过滤
- 封装结果并进行返回
MGET操作
基本流程
- 遍历请求,计算出每个doc的路由信息,得到由shardid为key组成的request map
- 循环处理组织号的每个shard级请求,调用处理GET请求时使用的处理单个doc的流程
- 收集Response,全部Response返回后,执行finishHim(),给客户端返回结果
- 回复的消息中文档顺序与请求的顺序一致。如果部分文档读取失败,则不影响其它结果,检索失败的doc会在回复信息中标出
SEARCH操作
搜索类型
- DFS_QUERY_THEN_FETCH,dfs查询阶段的流程要多一些,它使用全局信息来获取更准确的评分
- QUERY_THEN_FETCH(默认)
搜索流程
原始数据(文本)
- 精确值搜索
- 比如日期和用户id、IP地址等
- 对精确值的比较是二进制的,查询要么匹配,要么不匹配
- 全文检索
- 指文本内容,比如一条日志,或者邮件的内容
- 全文内容的查询无法给出"有"还是"没有"的结果,它只能找到结果是"看起来像"你要查询的东西
- 因此把查询结果按照相似度排序,评分越高,相似度越大
文本分析器
通过分析器对搜索的文本进行分析
- 字符过滤器,· 主要对字符串进行预处理,例如,去掉HTML,将&转化成and
- 分词器,将字符串分割为单个词条,例如,根据空格和标点符号分割,输出的词条称为词元(Token)
- Token过滤器,根据停止词(Stop word)删除词元,例如and、the等无用词,或者根据同义词表增加词条
- 语言处理,对上一步得到的Token做一些和语言相关的处理,例如,转为小写,以及将单词转换为词根的形式。语言处理组件输出的结果称为词(Term)
建立索引
- 分析完毕后,将分析器输出的词(Term)传递给索引组件,生成倒排和正排索引,再存储到文件系统中
执行搜索
- 精确值搜索
- 调用Lucene完成
- 全文检索
- 对检索字段使用建立索引时相同的分析器进行分析,产生Token列表
- 根据查询语句的语法规则转换成一颗语法树
- 查找符合语法树的文档
- 对匹配到的文档列表进行相关性评分,评分策略一般使用TF/IDF
- 根据评分结果进行排序
分布式搜索过程
协调节点流程
- 查询(Query)阶段
- 将查询广播到索引中每个分片或副分片中
- 每个分片在本地执行搜并构建一个匹配文档的优先队列,大小为from + size的有序队列中
- 每个分片返回各自优先队列中所有文档的ID和排序值给协调节点,协调节点合并这些值到自己的优先队列中,产生一个全局排序后的列表
- 查询阶段并不会对搜索请求的内容进行解析,无论搜索什么内容,只看本次搜索需要命中哪些shard,然后正对每个特定shar选择一个副本,转发搜索请求
- 取回(Fetch)阶段
- 协调节点向本次搜索相关节点发送GET请求
- 分片所在节点向协调节点返回数据
- 协调节点等待所有文档被取回,然后返回给客户端
- 为了避免在协调节点中创建的优先队列过大,应尽量控制分页深度
- 该阶段的目的是通过文档ID获取完整的文档内容
数据节点流程
-
响应Query请求流程
- 执行查询,然后发送Response
- 慢查询Query日志的统计时间在于本阶段的处理时间
- 聚合操作在本阶段实现,在Lucene检索后完成
-
响应Fetch请求流程
- 执行fetch,然后发送Response
-
核心功能
- execute(),通过调用Lucene、searcher.serach()实现搜索
- rescorePhase,全文检索且需要打分
- suggestPhase,自动补全及纠错
- aggregationPhase,实现聚合
拓展
- 聚合是在ES中实现的,而非Lucene
- Query和Fetch请求之间是无状态的,除非是scroll方式
- 分页搜索不会单独缓存(cache),缓存和分页没有关系
- 每次分页的请求都是一次重新搜索的过程,而不是从第一次搜索的结果中获取
- 搜索需要遍历分片素有的Lucene分段,因此合并Lucene分段对搜索性能有好处
读取优化
优化思路
- 系统资源
- 数据索引方式
- 查询方式
优化方式
- 为文件系统cache预留足够的内存
- 通常,应用程序的读写都会被操作系统"cache",cache保存在系统物理内存中(线上应该禁用swap),命中cache可以降低对磁盘的直接访问频率
- 从磁盘读取数据,会产生一定的延迟。从系统cache中读取可以避免这种情况,更大的内存有更高的cache命中率,因此至少为系统cache预留一半的可用物理内存
- 使用更快的硬件
- 搜索类型属于计算比较多,可用考虑使用更快的CPU
- 使用SSD会比旋转类存储介质好很多
- 尽量避免使用NFS等远程文件系统
- 文档模型
- 合理设计文档模型
- 应该避免join操作
- 嵌套(nested)会使查询慢几倍
- 父子(parent-child)关系可能使查询慢数百倍
- 通过冗余提升搜索速度
- 预索引数据(文档富化)
- 可用通过某些查询的模式来优化数据的索引方式,在建立索引时,对文档进行富化
- 字段映射
- 有些字段的内容是数值,但并不意味着其总是应该被映射为数值类型
- 避免使用脚本
- 如果一定要用,则应该优先考虑painless和expressions
- 优化日期搜索
- 使用now的查询通常不能缓存,因为匹配到的范围一直在变化
- 可用将日期四舍五入到某个固定时间(如:年-月-日 小时这种格式),进行查询
- 只为读索引执行force-merge
- 基于日期进行轮询的索引的旧数据一般都不会再更新
- 为不再更新的只读索引执行force merge,将Lucene索引合并为单个分段,可用提升查询速度
- 可用在每天选一个时间点,对昨天的索引执行force-merge、shrink等操作
- 预热全局序列(Global ordinals)
- 全局序号是一种数据结构,用于在keyword字段上允许terms聚合
- 默认情况下,它们被延迟构建,因为ES不知道哪些字段将用于terms聚合,哪些字段不会
- 可用通过配置映射在刷新(refresh)时告诉ES预先加载全局序数
- execution hint
- 预热文件系统cache
- 通过指定文件拓展名,显式地告诉操作系统应该将哪些文件加载到内存中
- 转化查询表达式
- 在组合查询中可用通过bool过滤器进行and、or和not的多个逻辑组合检索
- 调节搜索请求中的batched_reduce_size
- 该字段是搜索请求中的一个参数
- 默认情况下,聚合操作在协调节点需要等所有的分片都取回结果后才执行,使用该参数可用不等待全部分片返回结果,而是在指定数量的分片返回结果之后就可以先处理一部分reduce
- 这样可用避免协调节点在等待结果时占用大量内存,避免极端情况下可能导致的OOM
- 使用近似聚合
- 近似聚合以牺少量的精度为代价,大幅提高了执行效率,降低了内存使用
- 深度优先还是广度优先
- ES有两种不同的聚合方式,深度优先和广度优先
- 深度优先是默认设置,先构建完整的树,然后修剪无用节点
- 限制搜索请求的分片数
- 一个搜索请求涉及的分片数量越多,协调节点的CPU和内存压力越大
- ES会拒绝超过1000个分片的搜索请求
- 我们应该更好的组织数据,让搜索请求的分片数量更少
- 利用自适应副本选择(ARS)提升ES响应速度
索引恢复
简述
- 索引恢复(indices.recovery)是ES数据恢复过程
- 待恢复的数据是客户端写入成功,但未执行刷盘(Flush)的Lucene分段
索引恢复分类(分片性质)
主分片恢复
- 简述
- 主分片从translog中自我恢复,尚未执行flush到磁盘的Lucene分段可以从translog中重建
- 流程
副分片恢复
- 简述
- 副分片需要从主分片中拉取Lucene分段和translog进行恢复,但是有机会跳过拉取Lucene分段的过程
- 流程
索引恢复的触发条件
- 从快照备份恢复
- 节点加入和离开
- 索引的_open操作
恢复时的几个阶段
- INIT,恢复尚未启动
- INDEX,恢复Lucene文件,以及在节点间复制索引数据
- VERIFY_INDEX,验证索引
- TRANSLOG,启动engine,重放translog,建立Lucene索引
- FINALIZE,清理工作
- DONE,完成
索引恢复流程的相关配置
保证副分片和主分片一致性
恢复(recovery)相关监控命令
- _cat/recovery
- 列出活跃的和已完成的recovery信息
- {index}/_recovery
- 查看特定索引的recovery所处阶段,以及每个分片、每个阶段的详细信息
- _stats
- 可以查看分片级信息,包括sync_id、local_checkpoint、global_checkpoint等
- 可以通过指定索引名称查看索引信息,或者使用_all输出全部索引信息
Shrink原理分析
简述
- 其可以缩小主分片的数量
- 其并不对源索引直接进行缩小操作,而是使用与源索引相同的配置创建一个新的索引,仅降低分片数
工作原理
- 以相同配置创建目标索引,但是降低主分片数量
- 从源索引的Lucene分段创建硬链接到目的索引,如果系统不支持硬链接,那么索引的所有分段都将复制到新索引,将会花费大量时间
- 对目标索引执行恢复操作,就像一个关闭的索引重新打开一样