elasticsearch存储结构
㈠ Elasticsearch
Elasticsearch是一个基于Lucene的实时分布式的搜索与分析引擎。Elasticsearch为所有类型的数据提供近乎实时的搜索和分析。无论结构化或非结构化文本、数字数据还是地理空间数据,Elasticsearch都可以有效地存储和索引,以支持快速搜索。随着你的数据和查询量的增长,Elasticsearch的分布式特性使部署能够随着它而无缝增长。
Elasticsearch是一个 分布式文档存储 。Elasticsearch不是将信息存储为列式数据行,而是存储已序列化为JSON文档的复杂数据结构。当集群中有多个Elasticsearch节点时,存储的文档会分布在整个集群中,并且可以从任何节点立即访问。
存储文档后,它会在近乎实时的情况下被索引并完全可搜索——1秒内。Elasticsearch使用一种称为倒排索引的数据结构,它支持非常快速的全文搜索。倒排索引列出了出现在任何文档中的每个唯一单词,并标识了每个单词出现的所有文档。
索引是文档的优化集合,每个文档都是字段的集合,字段是包含数据的键值对。 默认情况下,Elasticsearch对每个字段中的所有数据进行索引,并且每个索引字段都有一个专用的优化数据结构。
Elasticsearch还具有无预定数据模式(schema-less)的能力,这意味着无需明确指定如何处理文档中可能出现的每个不同字段即可对文档进行索引。启用动态映射后,Elasticsearch会自动检测新字段并将其添加到索引中。只要开始索引文档,Elasticsearch就会检测并将布尔值、浮点和整数值、日期和字符串映射到适当的Elasticsearch数据类型。也可以定义规则来控制动态映射,明确定义映射以完全控制字段的存储和索引方式。
Elasticsearch提供了一个简单REST API,用于管理集群以及索引和搜索数据。可以直接从命令行、应用程序客户端或通过Kibana中的开发者控制台轻松提交请求。
Elasticsearch REST API支持结构化查询、全文查询和将两者结合的复杂查询。结构化查询类似于在sql中构造的查询类型。全文查询查找与查询字符串匹配的所有文档,并按与搜索词的匹配程度对它们进行排序。
除了搜索单个术语之外,还可以执行短语搜索、相似性搜索和前缀搜索。可以使用 Elasticsearch全面的JSON样式查询语言 (Query DSL) 访问所有这些搜索功能。 您还可以构建SQL样式的查询以在Elasticsearch内本地搜索和聚合数据。
建议使用三个主节点三个数据节点集群,这里是演示
环境规划
Index moles
Index management
可以通过Kibana Management或ILM API创建和管理索引生命周期策略。当您为Beats或Logstash Elasticsearch输出插件启用索引生命周期管理时,默认策略是自动配置的。
索引生命周期阶段共分为五个阶段:
在为日志或指标等时间序列数据编制索引时,不能无限期地写入单个索引。 为了满足索引和搜索性能要求并管理资源使用情况,写入索引直到满足某个阈值,然后创建一个新索引并开始写入它。 使用滚动索引能够达到以下效果:
ILM能够根据索引大小、文档计数或年龄自动滚动到新索引。 当触发 Rollover 时,会创建一个新索引,写入别名会更新为指向新索引,所有后续更新都会写入新索引。
索引生命周期操作
配置生命周期策略
启动和停止索引生命周期管理
命令使用均已运行用户执行
elasticsearch-keystore 命令管理 Elasticsearch 密钥库中的安全设置。
elasticsearch-node命令能够在节点上执行某些不安全的操作,这些操作只能在关闭时执行。 此命令允许您调整节点的角色,不安全地编辑集群设置,并且即使在与磁盘上的数据不兼容的情况下,也可以在灾难后恢复某些数据或启动节点。
创建、列出和删除基于文件的服务账户令牌。当创建第一个服务帐户令牌时,此命令会在 $ES_HOME/config 目录中创建一个 service_tokens 文件。 该文件默认不存在。Elasticsearch监视此文件的更改并动态重新加载它.
设置内置用户的密码。此命令仅供在Elasticsearch安全功能的初始配置期间使用。 它使用弹性引导密码来运行用户管理API请求。 如果Elasticsearch密钥库受密码保护,则必须先输入密钥库密码,然后才能为内置用户设置密码。 为弹性用户设置密码后,引导密码不再有效,无法使用该命令。
在某些情况下,分片副本的Lucene索引或事务日志可能会损坏。 elasticsearch-shard命令能够在无法自动恢复或从备份恢复的分片的良好副本时删除分片的损坏部分。运行elasticsearch-shard时,将丢失损坏的数据。在运行elasticsearch-shard之前停止Elasticsearch。
使用基于文件的用户身份验证,则可以使用elasticsearch-users命令添加和删除用户、分配用户角色和管理密码。
参考官方文档 REST APIs
快照是从正在运行的Elasticsearch集群中获取的备份。 可以拍摄整个集群的快照,包括其所有数据流和索引。 还可以仅对集群中的特定数据流或索引进行快照。必须先注册快照存储库,然后才能创建快照。
Elasticsearch以增量方式进行快照:快照过程只将数据复制到存储库中,而之前的快照还没有复制到那里,避免了不必要的重复工作或存储空间。这意味着可以安全地以最小的开销频繁地进行快照。这种增量只适用于单个存储库,因为存储库之间没有数据共享。快照在逻辑上也是相互独立的,即使是在一个存储库内:删除一个快照不会影响任何其他快照的完整性。
可以将快照恢复到正在运行的集群中,默认情况下包括快照中的所有数据流和索引。 也可以选择仅从快照恢复集群状态或特定数据流或索引。
可以使用快照生命周期管理来自动拍摄和管理快照。
快照包含构成索引或数据流支持索引的磁盘上数据结构的副本。这意味着快照只能被恢复到可以读取索引的Elasticsearch版本中。版本兼容图如下:
㈡ Elasticsearch之Doc Value与Fielddata
倒排索引在搜索包含指定term的doc时非常高效,但是在相反的操作时表现很差:查询一个文档中包含哪些term。具体来说,倒排索引在搜索时最为高效,但在排序、聚合等与指定filed相关的操作时效率低下,需要用 doc_values 。
倒排索引将term映射到包含它们的doc,而doc values将doc映射到它们包含的所有词项,下面是一个示例:
当数据被逆置之后,想要收集到 Doc_1 和 Doc_2 的唯一 token 会非常容易。获得每个文档行,获取所有的词项,然后求两个集合的并集。
其实,Doc Values本质上是一个序列化了的列式存储结构,非常适合排序、聚合以及字段相关的脚本操作。而且这种存储方式便于压缩,尤其是数字类型。压缩后能够大大减少磁盘空间,提升访问速度。下面是一个数字类型的 Doc Values示例:
列式存储意味着有一个连续的数据块: [100,1000,1500,1200,300,1900,4200] 。因为我们已经知道他们都是数字(而不是像文档或行中看到的异构集合),所以可以使用统一的偏移量来将他们紧紧排列。
而且,针对这样的数字有很多种压缩技巧。你会注意到这里每个数字都是 100 的倍数,Doc Values会检测一个段里面的所有数值,并使用一个最大公约数,方便做进一步的数据压缩。
比如,这个例子中可以用100作为公约数,那么以上数字就变为[1,10,15,12,3,19,42],可用很少的bit就能存储,节约了磁盘空间。一般来说,Doc Values按顺序来检测以下压缩方案:
String类型使用顺序表,按和数字类型类似的方式编码。String类型去重后排序,然后写入一个表中,并分配一个ID号,然后这些ID号就被当做数字类型的Doc Values。这意味着字符串享有许多与数字相同的压缩特点。
Doc Values是在字段索引时与倒排索引同时生成,而且生成以后是不可变的。
Doc Value 默认对除了 analyzed String 外的所有字段启用(因为分词后会生成很多token使得Doc Values效率降低)。但是当你知道某些字段永远不会进行排序、聚合以及脚本操作的时候可以禁用Doc Values以节约磁盘空间提升索引速度,示例如下:
以上配置以后,session_id字段就只能被搜索,不能被用于排序、聚合以及脚本操作了。
还可以通过设定doc_values为true,index为no来让字段不能被搜索但可以用于排序、聚合以及脚本操作:
Doc Value的特点就是快速、高效、内存友好,使用由linux kernel管理的文件系统缓存弹性存储。doc values在排序、聚合或与字段相关的脚本计算得到了高效的运用,任何需要查找某个文档包含的值的操作都必须使用它。如果你确定某个filed不会做字段相关操作,可以直接关掉doc_values,节约内存,加快访问速度。
上文说过,在排序、聚合以及在脚本中访问field值时需要一个与倒排索引截然不同的数据访问模式:不同于倒排索引中的查找term->找到对应docs的过程,我们需要直接查找doc然后找到指定某个filed中包含的terms。
大多数field使用索引时、磁盘上的doc_values来支持这种访问模式,但是分词了的String filed不支持Doc Values,而是使用一种叫FieldData的数据结构。
FieldData主要是针对analyzed String ,它是一种查询时(query-time)的数据结构。
FieldData缓存主要应用场景是在对某一个field排序或者计算类的聚合运算时。它会把这个field列的所有值加载到内存,这样做的目的是提供对这些值的快速文档访问。为field构建FieldData缓存可能会很昂贵,因此建议有足够的内存来分配它,并保持其处于已加载状态。
FieldData是在第一次将该filed用于聚合,排序或在脚本中访问时按需构建 。FieldData是通过从磁盘读取每个段来读取整个反向索引,然后逆置term->doc的关系,并将结果存储在JVM堆中构建的。
所以,加载FieldData是开销很大的操作,一旦它被加载后,就会在整个段的生命周期中保留在内存中。
这了可以注意下FieldData和Doc Values的区别。较早的版本中,其他数据类型也是用的FieldData,但是目前已经用随文档索引时创建的Doc Values所替代。
JVM堆内存资源是非常宝贵的,能用好它对系统的高效稳定运行至关重要。FieldData是直接放在堆内的,所以必须合理设定用于存放它的堆内存资源数。ES中控制FieldData内存使用的参数是 indices.fielddata.cache.size ,可以用x%表示占该节点堆内存百分比,也可以用如12GB这样的数值。默认状况下,这个设置是无限制的,ES不会从FieldData中驱逐数据。如果生成的fielddata大小超过指定的size,则将驱逐其他值以腾出空间。使用时一定要注意,这个设置只是一个安全策略而并非内存不足的解决方案。因为通过此配置触发数据驱逐,ES会立刻开始从磁盘加载数据,并把其他数据驱逐以保证有足够空间,导致很高的IO以及大量的需要被垃圾回收的内存垃圾。
举个例子来说:每天为日志文件建一个新的索引。一般来说我们只对最近几天数据感兴趣,很少查询老数据。但是,按默认设置FieldData中的老索引数据是不会被驱逐的。这样的话,FieldData就会一直持续增长直到触发 熔断机制 ,这个机制会让你再也不能加载更多的FieldData到内存。这样的场景下,你只能对老的索引访问FieldData,但不能加载更多新数据。所以,这个时候就可以通过以上配置来把最近最少使用的FieldData驱逐以够新进来的数据腾空间。
FieldData是在数据被加载后再检查的,那么如果一个查询导致尝试加载超过可用内存的数据就会导致OOM异常。ES中使用了 FieldData Circuit Breaker 来处理上述问题,他可以通过分析一个查询涉及到的字段的类型、基数、大小等来评估所需内存。如果估计的查询大小大于配置的堆内存使用百分比限制,则断路器会跳闸,查询将被中止并返回异常。
断路器是工作是在数据加载前,所以你不用担心遇到FieldData导致的OOM异常。ES拥有多种类型的断路器:
可以根据实际需要进行配置。
FieldData是为分词String而生,它会消耗大量的java 堆空间,特别是加载基数(cardinality)很大的分词String filed时。但是往往对这种类型的分词Field做聚合是没有意义的。
值得注意的是,FieldData和Doc Values的加载时机不同,前者是首次查询时,后者是doc索引时。还有一点,FieldData是按每个段来缓存的。
doc_values与fielddata一个很显着的区别是,前者的工作地盘主要在磁盘,而后者的工作地盘在内存。
索引速度稍低这个是相对于fielddata方案的,其实仔细想想也可以理解。拿排序举例,相对于一个在磁盘排序,一个在内存排序,谁的速度快不言自明。
在ES 1.x版本的官方说法是,
虽然速度稍慢,doc_values的优势还是非常明显的。一个很显着的点就是它不会随着文档的增多引起OOM问题。正如前面说的,doc_values在磁盘创建排序和聚合所需的正排索引。这样我们就避免了在生产环境给ES设置一个很大的 HEAP_SIZE ,也使得JVM的GC更加高效,这个又为其它的操作带来了间接的好处。
而且,随着ES版本的升级,对于doc_values的优化越来越好,索引的速度已经很接近fielddata了,而且我们知道硬盘的访问速度也是越来越快(比如SSD)。所以 doc_values 现在可以满足大部分场景,也是ES官方重点维护的对象。
所以我想说的是,doc values相比field data还是有很多优势的。所以 ES2.x 之后,支持聚合的字段属性默认都使用doc_values,而不是fielddata。
Global Ordinals是一个在Doc Values和FieldData之上的数据结构,它为每个唯一的term按字典序维护了一个自增的数字序列。每个term都有自己的一个唯一数字,而且字母A的全局序号小于字母B。特别注意,全局序号只支持String类型的field。
请注意,Doc Values和FieldData也有自己的ordinals序号,这个序号是特定segment和field中的唯一编号。通过提供Segment Ordinals和Global Ordinals间的映射关系,全局序号只是在此基础上创建,后者(即全局序号)是在整个shard分片中是唯一的。
一个特定字段的Global Ordinals跟一个分片中的所有段相关,而Doc Values和FieldData的ordinals只跟单个段相关。因此,只要是一个新段要变得可见,那么就必须完全重建全局序号。
也就是说,跟FieldData一样,在默认情况下全局序号也是懒加载的,会在第一个请求FieldData命中一个索引时来构建全局序号。实际上,在为每个段加载FieldData后,ES就会创建一个称为Global Ordinals(全局序号)的数据结构来构建一个由分片内的所有段中的唯一term组成的列表。
全局序号的内存开销小的原因是它由非常高效的压缩机制。提前加载的全局序号可以将加载时间从第一次搜索时转到全局序号刷新时。
全局序号的加载时间依赖于一个字段中的term数量,但是总的来说耗时较低,因为来源的字段数据都已经加载到内存了。
全局序号在用到段序号的时候很有用,比如排序或者terms aggregation,可以提升执行效率。
我们举个简单的例子。比如有十亿级别的doc,每个doc都有一个status字段,但只有pending, published, deleted三个状态数据。如果直接存整个String数据到内存,那么就算每个doc有15字节,那么一共就是差不多14GB的数据。怎么减少占用空间呢?首先想到的就是用数字来进行编码,码表如下:
这样的话,初始的那三个String就只在码表内被存了一次。FieldData中的doc就可以直接用编码来指向实际值:
这样编码以后,直接把数据量压缩了十倍左右。但有个问题是FieldData是按每个段来分别加载、缓存的。那么就会出现一个情况,如果一个段内的doc只有deleted和published两个状态,那么就会导致该FieldData算出来的码表只有0和1,这就和拥有3个状态的段算出的FieldData码表不同。这样的话,聚合的时候就必须一个段一个段的计算,最后再聚合,十分缓慢,开销巨大。
ES的做法是用Global Ordinals这种构建在FieldData之上的小巧数据结构,编码会结合所有段来计算唯一值然后存放为一个序号码表。这样一来,term aggregation可以只在全局序号上进行聚合,而且只会在聚合的最终阶段来计算从序号到真实的String值一次。这个机制可以提升聚合的性能3-4倍。
㈢ ElasticSearch 字段类型介绍
ElasticSearch对字符串拥有两种完全不同的搜索方式. 你可以按照整个文本进行匹配, 即关键词搜索(keyword search), 也可以按单个字符匹配, 即全文搜索(full-text search).
对ElasticSearch稍有了解的人都知道, 前者的字符串被称为not-analyzed字符, 而后者被称作analyzed字符串。
text用于全文搜索的, 而keyword用于关键词搜索.
(1)string
string类型在ElasticSearch 旧版本中使用较多,从ElasticSearch 5.x开始不再支持string,由text和keyword类型替代。
(2)text
当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。text类型的字段不用于排序,很少用于聚合。
(3)keyword
keyword类型适用于索引结构化的字段,比如email地址、主机名、状态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性为published的文章)、排序、聚合。keyword类型的字段只能通过精确值搜索到。
在满足需求的情况下,尽可能选择范围小的数据类型。比如,某个字段的取值最大值不会超过100,那么选择byte类型即可。迄今为止吉尼斯记录的人类的年龄的最大值为134岁,对于年龄字段,short足矣。字段的长度越短,索引和搜索的效率越高。
index分析
store存储
对于float、half_float和scaled_float,-0.0和+0.0是不同的值,使用term查询查找-0.0不会匹配+0.0,同样range查询中上边界是-0.0不会匹配+0.0,下边界是+0.0不会匹配-0.0。
其中scaled_float,比如价格只需要精确到分,price为57.34的字段缩放因子为100,存起来就是5734
优先考虑使用带缩放因子的scaled_float浮点类型。
index分析
store存储
日期类型表示格式可以是以下几种:
ElasticSearch 内部会将日期数据转换为UTC,并存储为milliseconds-since-the-epoch的long型整数。
例子:日期格式数据
逻辑类型(布尔类型)可以接受true/false/”true”/”false”值
二进制字段是指用base64来表示索引中存储的二进制数据,可用来存储二进制形式的数据,例如图像。默认情况下,该类型的字段只存储不索引。二进制类型只支持index_name属性。
在ElasticSearch中,没有专门的数组(Array)数据类型,但是,在默认情况下,任意一个字段都可以包含0或多个值,这意味着每个字段默认都是数组类型,只不过,数组类型的各个元素值的数据类型必须相同。在ElasticSearch中,数组是开箱即用的(out of box),不需要进行任何配置,就可以直接使用。
在同一个数组中,数组元素的数据类型是相同的,ElasticSearch不支持元素为多个数据类型:[ 10, “some string” ],常用的数组类型是:
ip类型的字段用于存储IPv4或者IPv6的地址
index分析
store存储
原文: https://blog.csdn.net/chengyuqiang/article/details/79048800
㈣ Elasticsearch之存储原理
倒排索引被写入磁盘后是不可变的,ES解决不变性和更新索引的方式是使用多个索引,利用新增的索引来反映修改,在查询时从旧的到新的依次查询,最后来一个结果合并。
ES底层是基于Lucene,最核心的概念就是 Segment(段) ,每个段本身就是一个倒排索引。
ES中的Index由多个段的集合和 commit point(提交点) 文件组成。
提交点文件中有一个列表存放着所有已知的段,下面是一个带有1个提交点和3个段的Index示意图:
Doc会先被搜集到内存中的Buffer内,这个时候还无法被搜索到,如下图所示:
每隔一段时间,会将buffer提交,在flush磁盘后打开新段使得搜索可见,详细过程如下:
下面展示了这个过程完成后的段和提交点的状态:
通过这种方式,可以使得新文档从被索引到可被搜索间的时间间隔在数分钟,但是还不够快。因为磁盘需要 fsync ,这个就成为性能瓶颈。我们前面提到过Doc会先被从buffer刷入段写入文件系统缓存(很快),那么就自然想到在这个阶段就让文档对搜索可见,随后再被刷入磁盘(较慢)。
Lucene支持对新段写入和打开,可以使文档在没有完全刷入硬盘的状态下就能对搜索可见,而且是一个开销较小的操作,可以频繁进行。
下面是一个已经将Docs刷入段,但还没有完全提交的示意图:
我们可以看到,新段虽然还没有被完全提交,但是已经对搜索可见了。
引入refresh操作的目的是提高ES的实时性,使添加文档尽可能快的被搜索到,同时又避免频繁fsync带来性能开销,依靠的就是文件系统缓存OS cache里缓存的文件可以被打开(open/reopen)和读取,而这个os cache实际是一块内存区域,而非磁盘,所以操作是很快的,这就是ES被称为近实时搜索的原因。
refresh默认执行的间隔是1秒,可以使用 refreshAPI 进行手动操作,但一般不建议这么做。还可以通过合理设置 refresh_interval 在近实时搜索和索引速度间做权衡。
index segment刷入到os cache后就可以打开供查询,这个操作是有潜在风险的,因为os cache中的数据有可能在意外的故障中丢失,而此时数据必备并未刷入到os disk,此时数据丢失将是不可逆的,这个时候就需要一种机制,可以将对es的操作记录下来,来确保当出现故障的时候,已经落地到磁盘的数据不会丢失,并在重启的时候可以从操作记录中将数据恢复过来。elasticsearch提供了translog来记录这些操作,结合os cached segments数据定时落盘来实现数据可靠性保证(flush)。
文档被添加到buffer同时追加到translog:
进行 refresh 操作,清空buffer,文档可被搜索但尚未 flush 到磁盘。translog不会清空:
每隔一段时间(例如translog变得太大),index会被flush到磁盘,新的translog文件被创建,commit执行结束后,会发生以下事件:
下面示意图展示了这个状态:
translog记录的是已经 在内存生成(segments)并存储到os cache但是还没写到磁盘的那些索引操作 (注意,有一种解释说,添加到buffer中但是没有被存入segment中的数据没有被记录到translog中,这依赖于写translog的时机,不同版本可能有变化,不影响理解),此时这些新写入的数据可以被搜索到,但是当节点挂掉后这些未来得及落入磁盘的数据就会丢失,可以通过trangslog恢复。
当然translog本身也是磁盘文件,频繁的写入磁盘会带来巨大的IO开销,因此对translog的追加写入操作的同样操作的是os cache,因此也需要定时落盘(fsync)。translog落盘的时间间隔直接决定了ES的可靠性,因为宕机可能导致这个时间间隔内所有的ES操作既没有生成segment磁盘文件,又没有记录到Translog磁盘文件中,导致这期间的所有操作都丢失且无法恢复。
translog的fsync是ES在后台自动执行的,默认是每5秒钟主动进行一次translog fsync,或者当translog文件大小大于512MB主动进行一次fsync,对应的配置是 index.translog.flush_threshold_period 和 index.translog.flush_threshold_size 。
当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。
translog 也被用来提供实时 CRUD 。当你试着通过ID来RUD一个Doc,它会在从相关的段检索之前先检查 translog 中最新的变更。
默认 translog 是每5秒或是每次请求完成后被 fsync 到磁盘(在主分片和副本分片都会)。也就是说,如果你发起一个index, delete, update, bulk请求写入translog并被fsync到主分片和副本分片的磁盘前不会反回200状态。
这样会带来一些性能损失,可以通过设为异步fsync,但是必须接受由此带来的丢失少量数据的风险:
flush 就是执行commit清空、干掉老translog的过程。默认每个分片30分钟或者是translog过于大的时候自动flush一次。可以通过flush API手动触发,但是只会在重启节点或关闭某个索引的时候这样做,因为这可以让未来ES恢复的速度更快(translog文件更小)。
满足下列条件之一就会触发冲刷操作:
整体流程:
删除一个ES文档不会立即从磁盘上移除,它只是被标记成已删除。因为段是不可变的,所以文档既不能从旧的段中移除,旧的段也不能更新以反映文档最新的版本。
ES的做法是,每一个提交点包括一个 .del 文件(还包括新段),包含了段上已经被标记为删除状态的文档。所以,当一个文档被做删除操作,实际上只是在 .del 文件中将该文档标记为删除,依然会在查询时被匹配到,只不过在最终返回结果之前会被从结果中删除。ES将会在用户之后添加更多索引的时候,在后台进行要删除内容的清理。
文档的更新操作和删除是类似的:当一个文档被更新,旧版本的文档被标记为删除,新版本的文档在新的段中索引。
该文档的不同版本都会匹配一个查询,但是较旧的版本会从结果中删除。
通过每秒自动刷新创建新的段,用不了多久段的数量就爆炸了,每个段消费大量文件句柄,内存,cpu资源。更重要的是,每次搜索请求都需要依次检查每个段。段越多,查询越慢。
ES通过后台合并段解决这个问题。ES利用段合并的时机来真正从文件系统删除那些version较老或者是被标记为删除的文档。被删除的文档(或者是version较老的)不会再被合并到新的更大的段中。
可见,段合并主要有两个目的:
ES对一个不断有数据写入的索引处理流程如下:
合并过程如图:
从上图可以看到,段合并之前,旧有的Commit和没Commit的小段皆可被搜索。
段合并后的操作:
合并完成后新的段可被搜索,旧的段被删除,如下图所示:
注意 :段合并过程虽然看起来很爽,但是大段的合并可能会占用大量的IO和CPU,如果不加以控制,可能会大大降低搜索性能。段合并的optimize API 不是非常特殊的情况下千万不要使用,默认策略已经足够好了。不恰当的使用可能会将你机器的资源全部耗尽在段合并上,导致无法搜索、无法响应。
㈤ Elasticsearch是什么以及核心概念
Elasticsearch是由Shay Banon发起的一个开源搜索服务器项目,2010年2月发布。迄今,该项目已发展成为搜索和数据分析解决方案领域的主要一员,广泛应用于声名卓着或鲜为人知的搜索应用程序。此外,由于其分布式性质和实时功能,许多人把它作为文档数据库。 Elasticsearch架构简单介绍如下。 索引 索引(index)是Elasticsearch对逻辑数据的逻辑存储,所以它可以分为更小的部分。你可以把索引看成关系型数据库的表。然而,索引的结构是为快速有效的全文索引准备的,特别是它不存储原始值。如果你知道MongoDB,可以把Elasticsearch的索引看成MongoDB里的一个集合。如果你熟悉CouchDB,可以把索引看成CouchDB数据库索引。Elasticsearch可以把索引存放在一台机器或者分散在多台服务器上,每个索引有一或多个分片(shard),每个分片可以有多个副本(replica)。 文档 存储在Elasticsearch中的主要实体叫文档(document)。用关系型数据库来类比的话,一个文档相当于数据库表中的一行记录。当比较Elasticsearch中的文档和MongoDB中的文档,你会发现两者都可以有不同的结构,但Elasticsearch的文档中,相同字段必须有相同类型。这意味着,所有包含title字段的文档,title字段类型都必须一样,比如string。 文档由多个字段组成,每个字段可能多次出现在一个文档里,这样的字段叫多值字段(multivalued)。每个字段有类型,如文本、数值、日期等。字段类型也可以是复杂类型,一个字段包含其他子文档或者数组。字段类型在Elasticsearch中很重要,因为它给出了各种操作(如分析或排序)如何被执行的信息。幸好,这可以自动确定,然而,我们仍然建议使用映射。与关系型数据库不同,文档不需要有固定的结构,每个文档可以有不同的字段,此外,在程序开发期间,不必确定有哪些字段。当然,可以用模式强行规定文档结构。从客户端的角度看,文档是一个JSON对象(关于JSON格式的更多内容,参见中国en.wikipedia.org/wiki/JSON)。每个文档存储在一个索引中并有一个Elasticsearch自动生成的唯一标识符和文档类型。文档需要有对应文档类型的唯一标识符,这意味着在一个索引中,两个不同类型的文档可以有相同的唯一标识符。 文档类型 在Elasticsearch中,一个索引对象可以存储很多不同用途的对象。例如,一个博客应用程序可以保存文章和评论。文档类型让我们轻易地区分单个索引中的不同对象。每个文档可以有不同的结构,但在实际部署中,将文件按类型区分对数据操作有很大帮助。当然,需要记住一个限制,不同的文档类型不能为相同的属性设置不同的类型。例如,在同一索引中的所有文档类型中,一个叫title的字段必须具有相同的类型。 映射 在有关全文搜索基础知识部分,我们提到了分析的过程:为建索引和搜索准备输入文本。文档中的每个字段都必须根据不同类型做相应的分析。举例来说,对数值字段和从中国页抓取的文本字段有不同的分析,比如前者的数字不应该按字母顺序排序,后者的第一步是忽略HTML标签,因为它们是无用的信息噪音。Elasticsearch在映射中存储有关字段的信息。每一个文档类型都有自己的映射,即使我们没有明确定义。 现在,我们已经知道Elasticsearch把数据存储在一个或多个索引上,每个索引包含各种类型的文档。我们也知道了每个文档有很多字段,映射定义了Elasticsearch如何对待这些字段。但还有更多,从一开始,Elasticsearch就被设计为能处理数以亿计的文档和每秒数以百计的搜索请求的分布式解决方案。这归功于几个重要的概念,我们现在将更详细地描述。 节点和集群 Elasticsearch可以作为一个独立的单个搜索服务器。不过,为了能够处理大型数据集,实现容错和高可用性,Elasticsearch可以运行在许多互相合作的服务器上。这些服务器称为集群(cluster),形成集群的每个服务器称为节点(node)。 分片 当有大量的文档时,由于内存的限制、硬盘能力、处理能力不足、无法足够快地响应客户端请求等,一个节点可能不够。在这种情况下,数据可以分为较小的称为分片(shard)的部分(其中每个分片都是一个独立的Apache Lucene索引)。每个分片可以放在不同的服务器上,因此,数据可以在集群的节点中传播。当你查询的索引分布在多个分片上时,Elasticsearch会把查询发送给每个相关的分片,并将结果合并在一起,而应用程序并不知道分片的存在。此外,多个分片可以加快索引。 副本 为了提高查询吞吐量或实现高可用性,可以使用分片副本。副本(replica)只是一个分片的精确复制,每个分片可以有零个或多个副本。换句话说,Elasticsearch可以有许多相同的分片,其中之一被自动选择去更改索引操作。这种特殊的分片称为主分片(primary shard),其余称为副本分片(replica shard)。在主分片丢失时,例如该分片数据所在服务器不可用,集群将副本提升为新的主分片
㈥ elasticsearch系统
Elasticsearch 是位于 Elastic Stack 核心的分布式搜索和分析引擎。Logstash 和 Beats 有助于收集、聚合和丰富您的数据并将其存储在 Elasticsearch 中。Kibana 使您能够以交互方式探索、可视化和分享对数据的见解,并管理和监控堆栈。Elasticsearch 是索引、搜索和分析魔法发生的地方。
Elasticsearch为所有类型的数据提供近乎实时的搜索和分析。无论您拥有结构化或非结构化文本、数字数据还是地理空间数据,Elasticsearch都能以支持快速搜索的方式高效地存储和索引它。您可以超越简单的数据检索和聚合信息来发现数据中的趋势和模式。随着您的数据和查询量的增长,Elasticsearch的分布式特性使您的部署能够随之无缝增长。
相关内容:
cluster:代表一个集群,集群中有多个节点,其中有一个为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的。
shards:代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
replicas:代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
recovery:代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。
㈦ 分布式搜索引擎elasticsearch的架构原理
分布式搜索引擎:把大量的索引数据拆散成多块,每台机器放一部分,然 后利用多台机器对分散之后的数据进行搜索,所有操作全部是分布在多台机器上进行,形成了 完整的分布式的架构。
近实时,有两层意思:
集群包含多个节点,每个节点属于哪个集群都是通过一个配置来决定的,
Node 是集群中的一个节点,节点也有一个名称,默认是随机分配的。默认节点会去加入一个名 称为 elasticsearch 的集群。如果直接启动一堆节点,那么它们会自动组成一个elasticsearch 集群,当然一个节点也可以组成 elasticsearch 集群。
文档是 es 中最小的数据单元,一个 document 可以是1条客户数据、1条商品分类数据、1条 订单数据,通常用json 数据结构来表示。每个 index 下的 type,都可以存储多条 document。
1个 document 里面有多个 field,每个 field 就是1个数据字段。
es 集群多个节点,会自动选举1个节点为 master 节点,这个 master 节点其实就是干一些管理 的工作的,比如维护索引元数据、负责切换 primary shard 和 replica shard 身份等。要是 master 节点宕机了,那么会重新选举1个节点为 master 节点。 如果是非 master节点宕机了,那么会由 master 节点,让那个宕机节点上的 primary shard 的身 份转移到其他机器上的 replica shard。接着你要是修复了那个宕机机器,重启了之后,master 节点会控制将缺失的 replica shard 分配过去,同步后续修改的数据之类的,让集群恢复正常。 说得更简单1点,就是说如果某个非 master 节点宕机了,那么此节点上的 primary shard 不就 没了。那好,master 会让 primary shard 对应的 replica shard(在其他机器上)切换为 primary shard。如果宕机的机器修复了,修复后的节点也不再是 primary shard,而是 replica shard。
索引可以拆分成多个 shard ,每个 shard 存储部分数据。拆分多个 shard是有好处的,一是支持横向扩展,比如你数据量是 3T,3 个 shard,每个 shard 就 1T 的数据, 若现在数据量增加到 4T,怎么扩展,很简单,重新建1个有 4 个 shard 的索引,将数据导进 去;二是提高性能,数据分布在多个 shard,即多台服务器上,所有的操作,都会在多台机器 上并行分布式执行,提高了吞吐量和性能。 接着就是这个 shard 的数据实际是有多个备份,就是说每个 shard 都有1个 primary shard ,负责写入数据,但是还有多个 replica shard 。 primary shard 写入数据之后, 会将数据同步到其他几个 replica shard上去。
通过这个 replica 的方案,每个 shard 的数据都有多个备份,如果某个机器宕机了,没关系啊, 还有别的数据副本在别的机器上,这样子就高可用了。
总结:分布式就是两点,1.通过shard切片实现横向扩展;2.通过replica副本机制,实现高可用
基本概念
写数据过程:客户端通过hash选择一个node发送请求,这个node被称做coordinating node(协调节点),协调节点对docmount进行路由,将请求转发给到对应的primary shard,primary shard 处理请求,将数据同步到所有的replica shard,此时协调节点,发现primary shard 和所有的replica shard都处理完之后,就反馈给客户端。
客户端发送get请求到任意一个node节点,然后这个节点就称为协调节点,协调节点对document进行路由,将请求转发到对应的node,此时会使用随机轮询算法,在primary shard 和replica shard中随机选择一个,让读取请求负载均衡,接收请求的node返回document给协调节点,协调节点,返回document给到客户端
es最强大的是做全文检索,就是比如你有三条数据
1.java真好玩儿啊
2.java好难学啊
3.j2ee特别牛
你根据java关键词来搜索,将包含java的document给搜索出来。
更新/删除数据过程,首先还是write、merge操作,然后flush过程中:
1、write过程和上面的一致;
2、refresh过程有点区别
所谓的倒排索引,就是把你的数据内容先分词,每句话分成一个一个的关键词,然后记录好每一个关键词对应出现在了哪些 id 标识的数据。
然后你可以从其他地根据这个 id 找到对应的数据就可以了,这个就是倒排索引的数据格式 以及搜索的方式,这种利倒排索引查找数据的式,也被称之为全文检索。
Inverted Index就是我们常见的倒排索引, 主要包括两部分:
一个有序的数据字典 Dictionary(包括单词 Term 和它出现的频率)。
与单词 Term 对应的 Postings(即存在这个单词的文件)
当我们搜索的时候,首先将搜索的内容分解,然后在字典里找到对应 Term,从而查找到与搜索相关的文件内容。
本质上,Stored Fields 是一个简单的键值对 key-value。默认情况下,Stored Fields是为false的,ElasticSearch 会存储整个文件的 JSON source。
哪些情形下需要显式的指定store属性呢?大多数情况并不是必须的。从_source中获取值是快速而且高效的。如果你的文档长度很长,存储 _source或者从_source中获取field的代价很大,你可以显式的将某些field的store属性设置为yes。缺点如上边所说:假设你存 储了10个field,而如果想获取这10个field的值,则需要多次的io,如果从Stored Field 中获取则只需要一次,而且_source是被压缩过 的。
这个时候你可以指定一些字段store为true,这意味着这个field的数据将会被单独存储(实际上是存两份,source和 Stored Field都存了一份)。这时候,如果你要求返回field1(store:yes),es会分辨出field1已经被存储了,因此不会从_source中加载,而是从field1的存储块中加载。
Doc_values 本质上是一个序列化的 列式存储,这个结构非常适用于聚合(aggregations)、排序(Sorting)、脚本(scripts access to field)等操作。而且,这种存储方式也非常便于压缩,特别是数字类型。这样可以减少磁盘空间并且提高访问速度,ElasticSearch 可以将索引下某一个 Document Value 全部读取到内存中进行操作.
Doc_values是存在磁盘的
在es中text类型字段默认只会建立倒排索引,其它几种类型在建立倒排索引的时候还会建立正排索引,当然es是支持自定义的。在这里这个正排索引其实就是Doc Value。
即上文所描述的动态索引
往 es 写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache 中去。
es 的搜索引擎严重依赖于底层的 filesystem cache ,你如果给 filesystem cache 更多的 内存,尽量让内存可以容纳所有的 idx segment file 索引数据文件,那么你搜索的时候就 基本都是走内存的,性能会非常高。 性能差距究竟可以有多大?我们之前很多的测试和压测,如果走磁盘一般肯定上秒,搜索性能 绝对是秒级别的,1秒、5秒、10秒。但如果是走 filesystem cache ,是走纯内存的,那么一 般来说性能比走磁盘要高一个数量级,基本上就是毫秒级的,从几毫秒到几百毫秒不等。
那如何才能节约filesystem cache这部分的空间呢?
当写数据到ES时就要考虑到最小化数据,当一行数据有30几个字段,并不需要把所有的数据都写入到ES,只需要把关键的需要检索的几列写入。这样能够缓存的数据就会越多。 所以需要控制每台机器写入的数据最好小于等于或者略大于filesystem cache空间最好。 如果要搜索海量数据,可以考虑用ES+Hbase架构。用Hbase存储海量数据,然后ES搜索出doc id后,再去Hbase中根据doc id查询指定的行数据。
当每台机器写入的数据大于cache os太多时,导致太多的数据无法放入缓存,那么就可以把一部分热点数据刷入缓存中。
对于那些你觉得比较热的、经常会有人访问的数据,最好做个专门的缓存预热系统,就是 对热数据每隔一段时间,就提前访问一下,让数据进入 filesystem cache 里去。这样下 次别人访问的时候,性能肯定会好很多。
把热数据和冷数据分开,写入不同的索引里,然后确保把热索引数据刷到cache里。
在ES里最好不要用复杂的关联表的操作。当需要这样的场景时,可以在创建索引的时候,就把数据关联好。比如在mysql中需要根据关联ID查询两张表的关联数据:select A.name ,B.age from A join B where A.id = B.id,在写入ES时直接去把相关联数据放到一个document就好。
es 的分页是较坑的,为啥呢?举个例子吧,假如你每页是 10 条数据,你现在要查询第 100 页,实际上是会把每个 shard 上存储的前 1000 条数据都查到1个协调节点上,如果你有个 5 个 shard,那么就有 5000 条数据,接着协调节点对这 5000 条数据进行一些合并、处理,再获取到 最终第 100 页的 10 条数据。
分布式的,你要查第 100 页的 10 条数据,不可能说从 5 个 shard,每个 shard 就查 2 条数据, 最后到协调节点合并成 10 条数据吧?你必须得从每个 shard 都查 1000 条数据过来,然后根据 你的需求进行排序、筛选等等操作,最后再次分页,拿到里面第 100 页的数据。你翻页的时 候,翻的越深,每个 shard 返回的数据就越多,而且协调节点处理的时间越长,非常坑爹。所 以用 es 做分页的时候,你会发现越翻到后面,就越是慢。
我们之前也是遇到过这个问题,用 es 作分页,前几页就几十毫秒,翻到 10 页或者几十页的时 候,基本上就要 5~10 秒才能查出来一页数据了。
解决方案吗?
1)不允许深度分页:跟产品经理说,你系统不允许翻那么深的页,默认翻的越深,性能就越差;
2)在APP或者公众号里,通过下拉来实现分页,即下拉时获取到最新页,可以通过scroll api来实现;
scroll 会1次性给你生成所有数据的1个快照,然后每次滑动向后翻页就是通过游标 scroll_id 移动获取下一页,性能会比上面说的那种分页性能要高很多很 多,基本上都是毫秒级的。 但是,唯1的缺点就是,这个适合于那种类似微博下拉翻页的,不能随意跳到任何一页的场 景。也就是说,你不能先进到第 10 页,然后去第 120 页,然后再回到第 58 页,不能随意乱跳 页。所以现在很多APP产品,都是不允许你随意翻页的,也有一些网站,做的就是你只能往 下拉,一页一页的翻。
初始化时必须指定 scroll 参数,告诉 es 要保存此次搜索的上下文多长时间。你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败。
除了用 scroll api ,也可以用 search_after 来做, search_after 的思想是使用前一页的结果来帮助检索下一页的数据,显然,这种方式也不允许你随意翻页,你只能一页一页往后 翻。初始化时,需要使用一个唯1值的字段作为 sort 字段。
㈧ 关于inner_hits
本文将从以下几个方面回答有关inner_hits的一些问题:
inner_hits是ElasticSearch进行nested,has_parent,has_child搜索时的一个选项,用来标记命中文档位置的。以官方文档中的例子为例。
索引”blog“有一个类型为”nested“的字段”comments“,我们写入了一个文档,其中包含了2个”comments“。下面我们对文档进行搜索,我们先不添加”inner_hits“看一下结果是怎么样:
可以看到,这个结果和正常搜索没有太多区别。
现在我们在搜索时加入”inner_hits“看一下效果,为了简单起见,”inner_hits“不使用任何选项。
我们可以看到结果比刚才多了一个”inner_hits“块:
可以看到,”inner_hits“中包含了关于此处文档的一些匹配信息,其中比较重要的有两个:
”nested“,告诉我们此次命中是文档中的那个nested字段,我们的例子里只有一个”nested“类型的字段,而实际上一个索引中,默认最多可以有50个”nested“类型的字段,这个值由索引的配置项” index.mapping.nested_fields.limit “控制。
”_source“,告诉我们当前命中的是哪个文档。我们的例子里,查询的条件是”number=2“,因此在 ”_source“部分返回了对应的那个文档。“inner_hits”有一个选项“_source”,默认值是true,如果将其置为false可以在返回结果中不显示”_source“的内容。
在ElasticSearch中,nested对象是以独立的隐藏文档的方式进行存储的,以上面的例子为例,id为1的文档,有2个comments类型的nested对象,最终存储在ES中的其实是三个文档。而relation类型的对象,父子文档的结构可以完全不同,却是存储在同一个索引中。在进行nested search或者has_child,has_parent search的时候我们可能需要知道,我们的搜索到底是匹配了哪些更细粒度的文档。因此需要inner_hits。
最简单的用法,如上文例子中使用的一样。直接加入一个空的“inner_hits”块即可。除此之外还有一些更细粒度的控制选项:
"from": 指定从文档内部对象array的某个位置开始显示inner_hits。比如说如果from指定为2,那么位置在0和1的文档即使在搜索中被匹配到了,也不会显示在inner_hits里。
"size": 最多显示inner_hits的文档数。
"sorted": 返回inner_hits 对象的排序字段。
"name": 当存在有多个nested字段在搜索中被涉及到时,指定其中某个字段作为inner_hits的显示字段。
更多可参考官方文档的内容
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/search-request-inner-hits.html
由于nested search,has_parent search,has_child search的文档对象存储方式,在进行相关搜索时,会涉及到主文档之外的其他文档,我们需要一种手段来指出命中的原因。inner_hits应运而生,它可以支持命中文档在多个文档组成的array中的位置,以及具体是哪个nested对象被命中了。总而言之,这是一种帮助我们理解搜索结果的方式或者手段。
㈨ Elasticsearch的架构是什么样的
Elasticsearch是由Shay Banon发起的一个开源搜索服务器项目,2010年2月发布。迄今,该项目已发展成为搜索和数据分析解决方案领域的主要一员,广泛应用于声名卓着或鲜为人知的搜索应用程序。此外,由于其分布式性质和实时功能,许多人把它作为文档数据库。
Elasticsearch架构简单介绍如下。
索引
索引(index)是Elasticsearch对逻辑数据的逻辑存储,所以它可以分为更小的部分。你可以把索引看成关系型数据库的表。然而,索引的结构是为快速有效的全文索引准备的,特别是它不存储原始值。如果你知道MongoDB,可以把Elasticsearch的索引看成MongoDB里的一个集合。如果你熟悉CouchDB,可以把索引看成CouchDB数据库索引。Elasticsearch可以把索引存放在一台机器或者分散在多台服务器上,每个索引有一或多个分片(shard),每个分片可以有多个副本(replica)。
文档
存储在Elasticsearch中的主要实体叫文档(document)。用关系型数据库来类比的话,一个文档相当于数据库表中的一行记录。当比较Elasticsearch中的文档和MongoDB中的文档,你会发现两者都可以有不同的结构,但Elasticsearch的文档中,相同字段必须有相同类型。这意味着,所有包含title字段的文档,title字段类型都必须一样,比如string。
文档由多个字段组成,每个字段可能多次出现在一个文档里,这样的字段叫多值字段(multivalued)。每个字段有类型,如文本、数值、日期等。字段类型也可以是复杂类型,一个字段包含其他子文档或者数组。字段类型在Elasticsearch中很重要,因为它给出了各种操作(如分析或排序)如何被执行的信息。幸好,这可以自动确定,然而,我们仍然建议使用映射。与关系型数据库不同,文档不需要有固定的结构,每个文档可以有不同的字段,此外,在程序开发期间,不必确定有哪些字段。当然,可以用模式强行规定文档结构。从客户端的角度看,文档是一个JSON对象(关于JSON格式的更多内容,参见http://en.wikipedia.org/wiki/JSON)。每个文档存储在一个索引中并有一个Elasticsearch自动生成的唯一标识符和文档类型。文档需要有对应文档类型的唯一标识符,这意味着在一个索引中,两个不同类型的文档可以有相同的唯一标识符。
文档类型
在Elasticsearch中,一个索引对象可以存储很多不同用途的对象。例如,一个博客应用程序可以保存文章和评论。文档类型让我们轻易地区分单个索引中的不同对象。每个文档可以有不同的结构,但在实际部署中,将文件按类型区分对数据操作有很大帮助。当然,需要记住一个限制,不同的文档类型不能为相同的属性设置不同的类型。例如,在同一索引中的所有文档类型中,一个叫title的字段必须具有相同的类型。
映射
在有关全文搜索基础知识部分,我们提到了分析的过程:为建索引和搜索准备输入文本。文档中的每个字段都必须根据不同类型做相应的分析。举例来说,对数值字段和从网页抓取的文本字段有不同的分析,比如前者的数字不应该按字母顺序排序,后者的第一步是忽略HTML标签,因为它们是无用的信息噪音。Elasticsearch在映射中存储有关字段的信息。每一个文档类型都有自己的映射,即使我们没有明确定义。
现在,我们已经知道Elasticsearch把数据存储在一个或多个索引上,每个索引包含各种类型的文档。我们也知道了每个文档有很多字段,映射定义了Elasticsearch如何对待这些字段。但还有更多,从一开始,Elasticsearch就被设计为能处理数以亿计的文档和每秒数以百计的搜索请求的分布式解决方案。这归功于几个重要的概念,我们现在将更详细地描述。
节点和集群
Elasticsearch可以作为一个独立的单个搜索服务器。不过,为了能够处理大型数据集,实现容错和高可用性,Elasticsearch可以运行在许多互相合作的服务器上。这些服务器称为集群(cluster),形成集群的每个服务器称为节点(node)。
分片
当有大量的文档时,由于内存的限制、硬盘能力、处理能力不足、无法足够快地响应客户端请求等,一个节点可能不够。在这种情况下,数据可以分为较小的称为分片(shard)的部分(其中每个分片都是一个独立的Apache Lucene索引)。每个分片可以放在不同的服务器上,因此,数据可以在集群的节点中传播。当你查询的索引分布在多个分片上时,Elasticsearch会把查询发送给每个相关的分片,并将结果合并在一起,而应用程序并不知道分片的存在。此外,多个分片可以加快索引。
副本
为了提高查询吞吐量或实现高可用性,可以使用分片副本。副本(replica)只是一个分片的精确复制,每个分片可以有零个或多个副本。换句话说,Elasticsearch可以有许多相同的分片,其中之一被自动选择去更改索引操作。这种特殊的分片称为主分片(primary shard),其余称为副本分片(replica shard)。在主分片丢失时,例如该分片数据所在服务器不可用,集群将副本提升为新的主分片。