【Elasticsearch系列之一】ES基本概念

1、Near Realtime 近实时

ES 是一个近实时的搜索平台,当一个文档写入Lucene后是不能被立即查询到的。Elasticsearch提供了一个refresh操作,会定时地调用lucene的reopen(新版本为openIfChanged)为内存中新写入的数据生成一个新的segment,此时被处理的文档均可以被检索到。refresh操作的时间间隔由refresh_interval参数控制,默认为1s, 可以在写入请求中带上refresh表示写入后立即refresh,另外还可以调用refresh API显式refresh,例如:

POST /refresh                     #刷新所有索引  POST /my_logs/_refresh   #刷新my_logs索引

注意:为了提高写性能,腾讯云Elasticsearch的refresh_interval参数的默认值设置的是30s, 要30s才能查到数据,客户可以设置 refresh_interval 参数来把30s变成1s, 在kibana里写入语法修改:

PUT /your_index/_settings { "index" : { "refresh_interval" : 1s } }

在生产环境中需要根据具体应用场景来调整refresh_interval 参数值,如果设置的过小,就会频繁的重载索引文件,导致请求变慢。建议对于搜索结果实时性不高的场景(日志检索等),可以适当增加refresh_interval参数值。

2、Cluster 集群

集群(cluster)是一组具有相同cluster.name的节点集合,他们协同工作,共同存储了所有数据,并提供了跨节点的联合索引和搜索功能,当然一个节点也可以组成一个集群,当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。

2.1、集群健康状态

集群状态通过 绿 来标识:

  • 绿色 – 一切都很好(集群功能齐全)。
  • 黄色 – 所有数据均可用,但尚未分配一些副本(集群功能齐全)。
  • 红色 – 某些数据由于某种原因不可用(集群部分功能)。

注意:当群集为红色时,它将继续提供来自可用分片的搜索请求,但您可能需要尽快修复它,因为存在未分配的分片。

要检查群集运行状况,我们可以在 Kibana 控制台中运行以下命令:

GET /_cluster/health

得到如下信息:

{    "cluster_name" : "es-p2wje7t7",    "status" : "green",    "timed_out" : false,    "number_of_nodes" : 5,    "number_of_data_nodes" : 2,    "active_primary_shards" : 35,    "active_shards" : 70,    "relocating_shards" : 0,    "initializing_shards" : 0,    "unassigned_shards" : 0,    "delayed_unassigned_shards" : 0,    "number_of_pending_tasks" : 0,    "number_of_in_flight_fetch" : 0,    "task_max_waiting_in_queue_millis" : 0,    "active_shards_percent_as_number" : 100.0  }

2.2、Master主节点

node.master设置为true(默认)的 节点,使其有资格被选为集群的Master节点。Master节点不负责数据的索引和检索,所以负载较轻。当Master节点失联或者挂掉的时候,ES集群会自动从其他Master节点选举出一个Leader。

为保证数据得一致性,只有Master节点可以修改信,Master节点负责同步集群状态信息如下:

1) 所有节点信息;

2) 所有索引即其 Mapping 和 Setting 信息;

3) 所有分片路由信息;

4) Master节点负责集群相关的操作,例如创建或删除索引,跟踪哪些节点是集群的一部分,以及决定将哪些分片分配给哪些节点。

建议:

因为索引和搜索数据都是CPU,内存和I/O密集型工作,可能会对节点资源造成压力,为确保Master节点稳定且不受压力,在实际生产环境中或较大的群集中,最好分割专用Master节点和专用Data节点之间的角色。

虽然Master节点也可以为协调节点,并将搜索和索引请求从客户端路由到数据节点,但为了集群的稳定性,建议用专用Master节点。创建专用的Master节点参数如下:

        node.master: true          node.data: false          node.ingest: false

如果使用 kibana 来作为视图操作工具的话,我们只需在kibana.yml的配置文件中,将elasticsearch.url: "http://localhost:9200"设置为Master节点就可以了,通过Master节点,ES会自动关联查询所有节点和分片以及副本的信息。所以 kibana 一般都和主节点在同一台服务器上。

对用户的访问是透明的,我们可以将请求发送到集群中的任何节点 ,包括主节点。 每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到存储我们所需文档的节点。 无论我们将请求发送到哪个节点,它都能负责从各个包含我们所需文档的节点收集回数据,并将最终结果返回给客户端。

2.3、发现机制

发现机制负责发现集群中的节点,以及选择Master节点。每次集群状态发生更改时,集群中的其他节点都会知道状态(具体方式取决于使用的是哪一种发现机制)。

ES目前主要推荐的自动发现机制,有如下几种:

1) Azure classic discovery 插件方式,多播;

2) EC2 discovery 插件方式,多播;

3) Google Compute Engine (GCE) discovery 插件方式,多播;

4) Zen discovery 默认实现,多播/单播。

Zen Discovery 是 ES 默认内建发现机制。它提供单播多播的发现方式,并且可以扩展为通过插件支持云环境和其他形式的发现。所以我们接下来重点介绍下 Zen Discovery是如何在Elasticsearch中使用的。

集群是由相同cluster.name的节点组成的。当您在同一台机器上启动了第二个节点时,只要它和第一个节点有同样的 cluster.name 配置,它就会自动发现集群并加入到其中。但是在不同机器上启动节点的时候,为了加入到同一集群,您需要配置一个可连接到的单播主机列表。

单播主机列表通过discovery.zen.ping.unicast.hosts来配置。这个配置在 elasticsearch.yml 文件中,具体配置如下:

discovery.zen.ping.unicast.hosts: ["host1", "host2:port"]

具体的值是一个主机数组或逗号分隔的字符串。每个值应采用host:port或host的形式(其中port默认为设置transport.profiles.default.port,如果未设置则返回transport.tcp.port)。注意在ES 7.0.0中,官方文档明确指出,和集群发现(Discovery)有关的配置主要由下面两个:

discovery.seed_hosts: ["10.10.3.9", "10.10.3.16", "10.10.3.2"]
#当第一次启动全新Elasticsearch集群时,会有一个集群引导(cluster bootstrapping)步骤,这个步骤会确定一个在第一次选举中投票被计数的、并且可以成为 master节点的集合  cluster.initial_master_nodes: ["Intel-node-1", "Intel-node-2", "Intel-node-3"]

另外,discovery.zen.ping.unicast.resolve_timeout 配置在每轮ping操作中等待DNS查找的时间。需要指定时间单位,默认为5秒。

单播发现(unicast discovery)应用 transport 模块实现发现(discovery)。使用单播,您可以为 Elasticsearch 提供一些它应该去尝试连接的节点列表。当一个节点联系到单播列表中的成员时,它就会得到整个集群所有节点的状态,然后它会联系 master节点,并加入集群。这意味着您的单播列表不需要包含集群中的所有节点,它只是需要足够的节点,当一个新节点联系上其中一个并且能正常通信就可以了。如果您使用 master 候选节点作为单播列表,只要列出三个就可以了。

Elasticsearch 官方推荐我们使用单播(默认)代替组播,虽然组播仍然作为插件提供, 但不建议在生产环境使用,否则可能导致一个节点意外收到了组播信号,而错误的加入到生产环境中。

2.3、选举Master节点

选举Mater节点会执行ping,其他节点加入某个集群也会执行ping,这个过程是自动执行的。通过配置discovery.zen.ping_timeout来控制节点加入某个集群或者开始选举的响应时间(默认3s)。

在这段时间内有3个 ping 会发出。如果超时,重新启动 ping 程序。在网络缓慢时,3秒时间可能不够,这种情况下,需要慎重增加超时时间,增加超时时间会减慢选举进程。

一旦节点决定加入一个存在的集群,它会发出一个加入请求给主节点,这个请求的超时时间由discovery.zen.join_time控制,默认是 ping 超时时间(discovery.zen.ping_timeout)的20倍。

当主节点停止或者出现问题,集群中的节点会重新 ping 并选举一个新节点。有时一个节点也许会错误的认为主节点已死,所以这种 ping 操作也可以作为部分网络故障的保护性措施。在这种情况下,节点将只从其他节点监听有关当前活动主节点的信息。

discovery.zen.minimum_master_nodes设置了最少有多少个备选主节点参加选举,同时也设置了一个主节点需要控制最少多少个备选主节点才能继续保持主节点身份。如果控制的备选主节点少于discovery.zen.minimum_master_nodes的个数,那么当前主节点下台,重新开始选举。

为了防止脑裂,通常设置参数为discovery.zen.minimum_master_nodes=N/2+1,其中N为集群中Master节点的个数。建议集群中Master节点的个数为奇数个,如3个或者5个。

2.4、Data Node数据节点

node.data设置为true(默认)的 节点,主要负责集群中数据的索引和检索,一般压力比较大。在生产环境中,建议和Master节点分开,避免因为Data Node节点出问题影响到Master节点。创建专用的Data Node节点的参数如下:

        node.master: false          node.data: true          node.ingest: false

2.5、Ingest node预处理节点

node.ingest设置为true(默认)的 节点。Ingest node可以看作是数据前置处理转换的节点,支持 pipeline管道设置,可以使用 ingest 对数据进行过滤、转换等操作,类似于 logstash 中 filter的作用,功能相当强大。可以把Ingest节点的功能抽象为:大数据处理环节的“ETL”——抽取、转换、加载。创建专用的Ingest node节点的参数如下:

        node.master: false          node.data: false          node.ingest: true

2.6、coordinating node协调节点

称为协调节点或者客户端节点,当主节点和数据节点配置都设置为false的时候,该节点只能处理路由请求,处理搜索,分发索引操作等,从本质上来说该客户节点表现为智能负载平衡器。独立的客户端节点在一个比较大的集群中是非常有用的,他协调主节点和数据节点,客户端节点加入集群可以得到集群的状态,根据集群的状态可以直接路由请求。

例如,搜索请求在两个阶段中执行(query 和 fetch),由接收客户端请求的节点协调:

Ø 在请求阶段,协调节点将请求转发到保存数据的数据节点。每个数据节点在本地执行

请求并将其结果返回给协调节点;

Ø 在收集fetch阶段,协调节点将每个数据节点的结果汇集为单个全局结果集。

默认每个节点都是 coordinating 节点,创建专用的协调节点,需要设置其他类型全部为 false,参数设置如下:

        node.master: false          node.data: false          node.ingest: false

2.7、节点类型对比

节点类型

作用

配置

注意事项

Master主节点

主节点负责轻量级的集群管理,例如: (1)创建和删除索引; (2)跟踪哪些节点是集群的一部分; (3)决定要分配给哪些节点的分片。 拥有稳定的主节点对集群监控很重要。

node.master: true node.data: false node.ingest: false

(1)任何具有主控资源的节点(默认都有)都可能被选举为主节点; (2)候选主节点之间出现了网络分区则可能会出现集群脑裂的情况,导致数据不一致或丢失,可以通过discovery.zen.minimum_master_nodes=N/2+1避免脑裂;

Data数据节点

数据节点保存包含索引文档的分片: (1)与CRUD、搜索和聚合相关的数据相关操作; (2)这些操作都是I/O、内存和CPU密集型; (3)如果监控到这些资源超载,就需要添加更多的数据节点。

node.master: false node.data: true node.ingest: false

Ingest预处理节点

(1)能执行预处理管道,有自己独立的任务要执行,类似于logstash的功能,不负责数据和集群相关的事务; (2)能够再索引之前预处理文档:拦截文档的bulk和index请求,转换,然后再将文档会给bulk和index api。用户可以定义一个管道,指定一系列的预处理器。

node.master: false node.data: false node.ingest: true search.remote.connect:false

(1)这个节点的负载会比较大,使用专用的节点作为ingest; (2)建议将主节点和数据节点的node.ingest属性设置为false。

Coordinating协调节点

(1)处理路由请求; (2)处理搜索聚合节点; (3)分发批量索引请求。

node.master: false node.data: false node.ingest: false search.remote.connect:false

(1)在大型集群中,建议将协调节点角色从数据节点和具有主控节点分离开来形成一个只协调节点; (2)加入集群并接受全部的集群状态信息,跟其他节点一样,使用集群状态信息来路由请求到合适的节点。

3、Document 文档

文档是构建索引的基本单元。例如,一条客户数据、一条产品数据、一条订单数据都可以是一个文档,文档以json格式表示。

4、Shard and Replicas 分片和副本

4.1、分片Shard

一个索引可以存储大量的数据,甚至超出单个节点的磁盘存储空间。例如,一个索引存储了数十亿文档,这些文件占用超过1T的磁盘空间,单台机器无法存储或者由于太多而无法提供搜索服务。

为了解决这个问题,ES 提供了将单个索引分割成多个分片的功能。创建索引时,可以指定任意数量的分片。每个分片都是一个功能齐全且独立的“index”,且可以被托管到集群中的任意节点上。分片有两个重要作用:

1) 它允许您水平拆分/缩放内容量;

2) 它允许您跨分片(可能在多个节点上)分布和并行化操作,从而提高性能/吞吐量。

4.2、副本Replicas

ES 允许为分片生成一个或多个副本,当在发生异常(不管什么原因导致分片下线或丢失)时有一定的容错机制。副本有两个重要作用:

1) 服务高可用:分片异常时,可以通过副本继续提供服务,因此分片副本不会与主分片分配到同一个节点;

2) 扩展性能:由于查询操作可以在分片副本上执行,因此可以提升系统的查询吞吐量。

5、index索引

index是具有某些类似特征的文档集合,可以理解为数据库的database。例如,可以创建店铺数据的索引,商品的索引以及订单数据的索引。

索引由名称标识(必须全部小写),在对文档执行索引,搜索,更新和删除操作时需要引用索引。

6、Type类型

类型,曾经是索引的逻辑类别,允许在同一索引中存储不同类型的文档,例如,一种类型用于用户,另一种类型用于博客帖子。

注意:官方ES 7.0.0及之后版本将移除映射中的type类型定义,之前版本会继续支持,详情请参见官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.3/removal-of-types.html#_what_are_mapping_types

如果在7.0.0及之后版本使用了type,会出现"type": "mapper_parsing_exception"的错误提示。

7、Mapping索引映射

在数据库建表的时候,一般都会指定每个字段的存储类型,例如:varchar,int,datetime等等,就是为了更精确的存储数据,防止数据类型格式混乱。在 Elasticsearch中也是这样,创建索引的时候一般也需要指定索引的字段类型、分词器及属性等,这种方式成为映射(Mapping),本质上就是index的Scheme。

7.1、字段数据类型(field datatypes)

每一个字段,都属于一种数据类型。数据库中有varchar,int,datetime等数据类型,ElasticSearch针对每一个字段,也都有相应的数据类型,具体如下:

1) 核心数据类型

Ø 字符串类型

主要包括:text 和 keyword

Ø 数值类型

主要包括:long, integer, short, byte, double, float, half_float, scaled_float

Ø 日期类型

date

Ø 布尔值类型

boolean

Ø 二进制类型

binary

Ø 范围类型

integer_range, float_range, long_range, double_range, date_range

text 和 keyword 的区别

text: 用于索引全文值的字段,例如,电子邮件正文或产品说明。这些字段是analyzed,它们通过分词器传递,以在被索引之前将字符串转换为单个术语的列表。分析过程允许Elasticsearch搜索单个单词中每个完整的文本字段。

keyword: 用于索引结构化内容的字段,例如电子邮件地址,主机名,状态代码,邮政编码或标签。它们通常用于过滤,排序,和聚合,keyword字段只能按其确切值进行搜索。

有时候一个字段可以同时设置为全文类型(text)和关键字类型(keyword):一个用于全文搜索,另一个用于聚合和排序,这可以通过多字段类型来实现。

2) 复杂数据类型

Ø Array数据类型(Array不需要定义特殊类型)

Ø Object数据类型 (json嵌套)

3) Geo数据类型

Ø 地理数据类型

geo_point 对于纬度/经度点

Ø Geo-Shape数据类型

geo_shape 对于像多边形这样的复杂形状

4) 专用数据类型

Ø ip(IPv4 and IPv6 addresses)

Ø completion(自动完成/搜索)

Ø token_count (数值类型,分析字符串,索引的数量)

Ø murmur3 (索引时计算字段值的散列并将它们存储在索引中的功能。 在高基数和大字符串字段上运行基数聚合时有很大帮助)

Ø join (同一索引的文档中创建父/子关系)

5) 多字段

有时候单纯的一个字段类型满足不了我们复杂的需求,为了不同的目的,可以用不同的方式索引同一个字段。多字段也是ES的一种数据类型,只不过结合了更多的功能。

例如,对于字符串字段,我们既可以将它映射为text类型用于全文搜索,也可以将它映射为keyword类型用于排序或聚合,或者还可以使用标准分词器、英语分词器和其他语言分词器索引文本字段。

大多数数据类型都通过fields参数支持多字段。例如,对于城市名称的多字段映射,可以这样写:

PUT my_index  {    "mappings": {      "_doc": {        "properties": {          "cityName": {            "type": "text",            "fields": {              "raw": {                "type":  "keyword"              }            }          }        }        }    }  }

以下是常用的参数字段类型定义&赋值demo:

类型

参数定义

赋值

text

"name":{"type":"text"}

"name": "zhangsan"

keyword

"tags":{"type":"keyword"}

"tags": "abc"

date

"date":{"type": "date"}

"date":"2015-01-01T12:10:30Z"

long

"age":{"type":"long"}

"age" :28

double

"score":{"type":"double"}

"score":98.8

boolean

"isgirl": { "type": "boolean" }

"isgirl" :true

ip

"ip_addr":{"type":"ip"}

"ip_addr": "192.168.1.1"

geo_point

"location": {"type":"geo_point"}

"location":{"lat":40.12,"lon":-71.34}

7.2、索引映射分类:

映射是定义一个文档及其包含的字段如何存储和索引的过程。例如,使用映射来定义:

Ø 应将哪些字符串字段视为全文字段。

Ø 哪些字段包含数字,日期或地理位置。

Ø 是否应将文档中所有字段的值索引到catch-all _all字段中。

Ø 日期值的格式。

Ø 自定义规则以控制动态添加字段的映射。

其实在 ElasticSearch中可以不需要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类型,但是通过这种自动识别的字段不是很精确,对于一些复杂的需要分词的就不适合了。根据是否自动识别映射类型,我们可以将映射分为动态映射静态映射

1) 动态映射 (dynamic mapping):即不需要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。

2) 静态映射 :动态映射的自动类型推测功能并不能保证100%正确的,这就需要静态映射。静态映射与关系数据库中创建表语句类型,需要事先指定字段类型。相对于动态映射,静态映射可以添加更加详细字段类型、更精准的配置信息等。

7.3、映射参数(Mapping parameters)

既然可以自定义映射字段类型,那么那些复杂的字段类型和分词器我们都可以根据自己需求添加了,以下提供了字段映射使用的各种映射参数的详细说明:

mapping parameters

备注

analyzer

指定分词器,对于text类型的字段,首先会使用分词器进行分词,然后将分词后的词根一个一个存储在倒排索引中,后续查询主要是针对词根的搜索。 analyzer该参数可以在查询、字段、索引级别中指定,其优先级如下(越靠前越优先): Ø 字段上定义的分词器 Ø 索引配置中定义的分词器 Ø 默认分词器(standard) 在查询上下文,分词器的查找优先为: Ø full-text query中定义的分词器 Ø 定义类型映射时字段中search_an alyzer定义的分词器 Ø 定义字段映射时analyzer定义的分词器 Ø 索引中default_search中定义的分词器 Ø 索引中默认定义的分词器 Ø 标准分词器(standard)

normalizer

normalizer 用在索引存储或者查询一个keyword类型的字段之前标准化配置,比如把所有的字符转化为小写等

boost

通过指定一个boost值来控制每个查询子句的相对权重,该值默认为1

coerce

coerce属性可以用来清除脏数据

copy_to

多字段的取值被复制到一个字段并且取值所有字段的取值组合, 并且可以当成一个单独的字段查询

doc_values

为了加快排序、聚合操作,在建立倒排索引的时候,额外增加一个列式存储映射,是一个空间换时间的做法。默认是开启的,对于确定不需要聚合或者排序的字段可以关闭

dynamic

用于配置新字段添加时的映射动作,默认情况下,字段可以自动添加到文档或者文档的内部对象,elasticsearc也会自动索引映射字段

enabled

ELasticseaech默认会索引所有的字段,enabled设为false的字段,elasicsearch会跳过字段内容,该字段只能从_source中获取,但是不可搜。而且字段可以是任意类型。

fielddata

默认情况下,字段数据在文本字段上禁用。对需要设置的text型字段设置fielddata = true,以便通过反转倒排索引来加载内存中的字段数据。注意,这可以使用大量的内存。

eager_global_ordinals

Global ordinals 是一个建立在 doc values 和 fielddata基础上的数据结构, 它为每一个精确词按照字母顺序维护递增的编号

format

JSON 文档内部,日期可能展现为字段串的样式. ElasticSearch 内部会将日期数据转换为UTC

ignore_above

超过 ignore_above 的字符串不会被索引

ignore_malformed

如果ignore_malformed参数设为true,异常会被忽略,出异常的字段不会被索引,其它字段正常索引

index_options

index_options 参数控制将哪些信息添加到倒排索引,用于搜索和突出显示目的

index

index 属性指定字段是否索引,不索引也就不可搜索,取值可以为true或者false

fields

fields可以让同一文本有多种不同的索引方式,比如一个String类型的字段,可以使用text类型做全文检索,使用keyword类型做聚合和排序。

norms

Norms 存储各种用于在查询时计算查询条件的相关性得分的标准化因子。虽然norms 在计算相关性得分时非常有用, 但是同样需要消耗大量内存

null_value

null_value 属性可以用指定的值替换空值,用于索引存储和检索

position_increment_gap

为了支持短语查询,需要保存可分词字符串中分词的位置

properties

类型映射、对象字段和嵌套类型字段包含的子字段成为属性。这些属性可以是任何的数据类型,包括对象和嵌套类型。 properties 在下面这些情况添加: Ø 创建索引的时候明确定义 Ø 利用 PUT mapping API 添加或者修改映射类型时明确定义 Ø 索引新字段时动态添加

search_analyzer

默认情况下,查询使用的分析器应该是字段映射中定义的分析器, 但是我们可以通过search_analyzer 重新设置

similarity

Elasticsearch 允许您为每个字段配置得分算法或者相似算法。similarity 提供了一个简单的算法来选择不同于默认BM25的相似算法, 例如 TF/IDF

store

默认情况下, 字段取值被索引以便于检索, 但是不会被存储,这就意味着字段可以被检索但是无法取到原始值。 通常情况下,这并不会有什么问题,字段的取值被默认存储在 _source 字段中。 如果您只是希望查询单个字段或者一些字段的值而不是整个_source, 您可以通过数据源过滤来实现。 在特定的情况下存储字段的值是有意义的。例如,一个文档具有 a title, a date, and a very large content , 您只是想倒排查询title 和date 而不是从整个_source检索。

term_vector

Term vectors 包含分析过程产生的索引词信息,包括: Ø 索引词列表 Ø 每个索引词的位置(或顺序) Ø 索引词在原始字符串中的原始位置中的开始和结束位置的偏移量。 term vectors 会被存储,索引它可以作为一个特使的文档返回。

Mapping 字段设置流程:

Mapping 字段设置流程

7.4、元数据字段(Meta-Fields)

每个文档都有与之关联的元数据,例如_index,_type和_id元字段。创建映射类型时,可以自定义其中一些元字段的行为,元数据字段包括:

1) 身份元数据字段:

a) _index文档所属的索引

b) _type文档的映射类型,索引的每个文档都与_type和_id关联。对该_type字段进行索引是为了使按名称快速搜索。

c) _id文档编号

添加数据时需要添加id来唯一标识文档。可以自己添加id,如果不添加,系统会自动生成id。

注意:用PUT方法添加文档时,需要手动指定id,用POST方法时,可以不指定,系统会自动生成id。示例如下:

# Example documents  PUT my_index/_doc/1  {  "text": "Document with ID 1"  }  PUT my_index/_doc/2?refresh=true  {  "text": "Document with ID 2"  }  GET my_index/_search  {  "query": {  "terms": {  "_id": [ "1", "2" ]    }  }  }

2) 文档源数据元字段:

a) _source表示文档正文的原始JSON

b) _size表示插件mapper-size提供的字段大小(以字节为单位)

3) 索引元数据字段:

a) _field_names表示文档中包含非空值的所有字段

b) _ignored由于导致索引时间被忽略的文档中的所有字段

4) 路由元数据字段:

a) 自定义的Routing模式

_routing一个自定义的路由值,用于将文档路由到特定的分片。

使用以下公式将文档路由到索引中的特定分片:

自定义routing计算公式

可以通过为routing 每个文档指定自定义值来实现自定义路由模式。例如:

PUT my_index/_doc/1?routing=user1&refresh=true  {         "title": "This is a document"  }  GET my_index/_doc/1?routing=user1 

本文档使用user1来代替ID路由,在get、delete、update时,需要提供相同的routing值。

这样使我们的查询更具目的性。我们不必盲目地去广播查询请求,取而代之的是:我们要告诉Elasticsearch我们的数据在哪个分片上。

原来的查询语句:“请告诉我,USER1的文档数量一共有多少”

使用自定义Routing(在USESR ID上)后的查询语句:“请告诉我,USER1的文档数量一共有多少,它就在第三个分片上,其它的分片就不要去扫描了”。

但是使用 routing的功能,大概率会出现分片大小不均匀的情况,对此 ES 采取的措施是,利用 _id 做二次路由,即相同 value 值,可以进入一个集群(shardList),而不是仅仅一个分片(shard),计算公式如下:

计算公式

b) 默认用文档ID路由

Elasticsearch建索引时默认是根据文档标识符_id 将文档均分至多个分片,这种算法基本上会保持所有数据在所有分片上的一个平均分布,而不会产生数据热点。当搜索数据时,默认查询所有分片结果然后汇总,而并不必须知道数据到底存在哪个分片上,具体的计算公式如下:

默认计算公式

假设有一个100个分片的索引。当一个请求在集群上执行时会发生什么呢?

Ø 这个搜索的请求会被发送到一个节点;

Ø 接收到这个请求的节点,将这个查询广播到这个索引的每个分片上(可能是主分片,也可能是副本分片);

Ø 每个分片执行这个搜索查询并返回结果;

Ø 结果在通道节点上合并、排序并返回给用户。

因为默认情况下,Elasticsearch使用文档的ID(类似于关系数据库中的自增ID,当然,如果不指定ID的话,Elasticsearch使用的是随机值)将文档平均的分布于所有的分片上,这导致了Elasticsearch不能确定文档的位置,所以它必须将这个请求广播到所有的100个分片上去执行。这同时也解释了为什么主分片的数量在索引创建的时候是固定下来的,并且永远不能改变。因为如果分片的数量改变了,所有先前的路由值就会变成非法了,文档相当于丢失了。

5) 其他元数据字段:

_meta特定于应用程序的元数据。