什么使用路由

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

  1. 这个搜索的请求会被发送到集群中的一个节点上
  2. 接收到这个请求的节点,将这个查询转到这个索引的每个分片上(可能是主分片,也可能是副本分片)
  3. 每个分片执行这个搜索查询并返回结果
  4. 结果在通道节点上合并、排序并返回给用户

因为默认情况下,Elasticsearch使用文档的ID(类似于关系数据库中的自增ID),如果插入数据量比较大,文档会平均的分布于所有的分片上,这导致了Elasticsearch不能确定文档的位置,所以它必须将这个请求转到所有的N个分片上去执行,这种操作会给集群带来负担,增大了网络的开销。

_search_shards API

那么如何确定请求在哪个分片上执行呢?Elasticsearch提供了一个API接口,告诉我们一个搜索请求在哪些节点和分片上执行。
比如我们创建一个两分片的索引:

put route_test
{"settings": {"index.number_of_shards": 2}
}

并放入数据:

put route_test/_doc/1
{"name": "doc1"
}put route_test/_doc/2
{"name": "doc2"
}put route_test/_doc/3
{"name": "doc3"
}put route_test/_doc/4
{"name": "doc4"
}

使用搜索分片(search shards)的API接口来查看请求将在哪些分片上执行。

get route_test/_search_shards?filter_path=shards{"shards" : [[{"state" : "STARTED","primary" : true,"node" : "0e-WRjOATYmkLfGuKdcVsg","relocating_node" : null,"shard" : 0,"index" : "route_test","allocation_id" : {"id" : "BxiXM7V4Sx-S3HOD8sBUAg"}}],[{"state" : "STARTED","primary" : true,"node" : "0e-WRjOATYmkLfGuKdcVsg","relocating_node" : null,"shard" : 1,"index" : "route_test","allocation_id" : {"id" : "J7Gmrp0SS9-OStreLOw3Fw"}}]]
}

可以看到,会搜索全部的两个分片。

带上路由进行搜索:

get route_test/_search_shards?routing=1&filter_path=shards{"shards" : [[{"state" : "STARTED","primary" : true,"node" : "0e-WRjOATYmkLfGuKdcVsg","relocating_node" : null,"shard" : 0,"index" : "route_test","allocation_id" : {"id" : "BxiXM7V4Sx-S3HOD8sBUAg"}}]]
}

即使在索引中只有两个分片,当指定路由值1的时候,只有分片shard 0会被搜索。对于搜索需要查找的数据,有效地切除了一半的数据量!所以当处理拥有大量分片的索引时,路由会很有价值,当然对于Elasticsearch的常规使用它并不是必需的。

配置路由

路由也可以不使用文档的ID,而是定制的数值进行散列。通过指定URL中的routing查询参数,系统将使用这个值进行散列,而不是ID。

PUT route_test/_doc/5?routing=rountkey
{"name": "doc5"
}

在这个例子中,rountkey这个由我们自己输入的值决定文档属于哪个分片的散列值,而不是文档的ID值2。

由上可知,自定义路由的方式非常简单,只需要在插入数据的时候指定路由的key即可。虽然使用简单,但有细节需要注意。我们来看看:

  1. 先创建一个名为study_route的索引,该索引有2个shard,0个副本
PUT study_route/
{"settings": {"number_of_shards": 2,"number_of_replicas": 0}
}
  1. 查看shard
get _cat/shards/study_route?vindex       shard prirep state   docs store ip         node
study_route 1     p      STARTED    0  230b 172.18.0.2 3f068cc83647
study_route 0     p      STARTED    0  230b 172.18.0.2 3f068cc83647
  1. 插入第1条数据
PUT study_route/_doc/a?refresh
{"data": "A"
}
  1. 查看shard
get _cat/shards/study_route?vindex       shard prirep state   docs store ip         node
study_route 1     p      STARTED    0  283b 172.18.0.2 3f068cc83647
study_route 0     p      STARTED    1 3.3kb 172.18.0.2 3f068cc83647
  1. 插入第2条数据
PUT study_route/_doc/b?refresh
{"data": "B"
}
  1. 查看shard
get _cat/shards/study_route?vindex       shard prirep state   docs store ip         node
study_route 1     p      STARTED    1 3.3kb 172.18.0.2 3f068cc83647
study_route 0     p      STARTED    1 3.3kb 172.18.0.2 3f068cc83647

这个例子比较简单,先创建了一个拥有2个shard,0个副本的索引study_route。创建完之后查看两个shard的信息,此时 shard为空,里面没有任何文档(docs列为0)。接着我们插入了两条数据,每次插完之后,都检查shard的变化。通过对比可以发现_id=a的第一条数据写入了shard 0,_id=b的第二条数据写入了shard 1。

接着,我们指定routing,看看有什么变化。

  1. 插入第3条数据
PUT study_route/_doc/c?routing=key1&refresh
{"data": "C"
}
  1. 查看shard
index       shard prirep state   docs store ip         node
study_route 1     p      STARTED    1 3.4kb 172.18.0.2 3f068cc83647
study_route 0     p      STARTED    2 6.8kb 172.18.0.2 3f068cc83647

我们又插入了1条_id=c的新数据,但这次我们指定了路由,路由的值是一个字符串"key1"。通过查看shard信息,能看出这条数据路由到了shard 0。也就是说用“key1”做路由时,文档会写入到shard 0。

接着我们使用该路由再插入两条数据,但这两条数据的_id分别为之前使用过的“a”和“b”,最终结果会是什么样?

  1. 插入_id=a的数据,并指定routing=key1
PUT study_route/_doc/a?routing=key1&refresh
{"data": "A with routing key1"
}{"_index" : "study_route","_type" : "_doc","_id" : "a","_version" : 2,"result" : "updated","forced_refresh" : true,"_shards" : {"total" : 1,"successful" : 1,"failed" : 0},"_seq_no" : 2,"_primary_term" : 1
}

es的返回信息表明文档a是updated。

  1. 插入_id=b的数据,使用key1作为路由字段的值
PUT study_route/_doc/b?routing=key1&refresh
{"data": "B with routing key1"
}{"_index" : "study_route","_type" : "_doc","_id" : "b","_version" : 1,"result" : "created","forced_refresh" : true,"_shards" : {"total" : 1,"successful" : 1,"failed" : 0},"_seq_no" : 3,"_primary_term" : 1
}

es返回的信息变成了created。

  1. 查看shard信息
get _cat/shards/study_route?vindex       shard prirep state   docs  store ip         node
study_route 1     p      STARTED    1  3.4kb 172.18.0.2 3f068cc83647
study_route 0     p      STARTED    3 13.9kb 172.18.0.2 3f068cc83647
  1. 查询索引内容
GET study_route/_search?filter_path=hits{"hits" : {"total" : {"value" : 4,"relation" : "eq"},"max_score" : 1.0,"hits" : [{"_index" : "study_route","_type" : "_doc","_id" : "c","_score" : 1.0,"_routing" : "key1","_source" : {"data" : "C"}},{"_index" : "study_route","_type" : "_doc","_id" : "a","_score" : 1.0,"_routing" : "key1","_source" : {"data" : "A with routing key1"}},{"_index" : "study_route","_type" : "_doc","_id" : "b","_score" : 1.0,"_routing" : "key1","_source" : {"data" : "B with routing key1"}},{"_index" : "study_route","_type" : "_doc","_id" : "b","_score" : 1.0,"_source" : {"data" : "B"}}]}
}

存在两个_id为b的文档,其中一个比另一个多了一个字段“_routing”。

这个就是我们自定义routing后会导致的一个问题:_id不再全局唯一。ES shard的实质是Lucene的索引,所以其实每个shard都是一个功能完善的倒排索引。ES能保证_id全局唯一是采用_id作为了路由,所以同样的_id肯定会路由到同一个 shard上面,如果出现_id重复,就会update或者抛异常,从而保证了集群内_id唯一标识一个doc。但如果我们换用其它值做routing,那这个就保证不了了,如果用户还需要_id的全局唯一性,那只能自己保证了。

因为_id不再全局唯一,所以doc的增删改查API就可能产生问题,比如下面的查询:

get study_route/_doc/b?filter_path=_source{"_source" : {"data" : "B"}
}get study_route/_doc/b?routing=key1&filter_path=_source{"_source" : {"data" : "B with routing key1"}
}

上面两个查询,虽然指定的_id都是b,但返回的结果是不一样的。所以,如果自定义了routing字段的话,一般doc的增删改查接口都要加上routing参数以保证一致性。

为此,ES在mapping中提供了一个选项,可以强制检查doc的增删改查接口是否加了routing参数,如果没有加,就会报错。

设置方式如下:

PUT study_route1/
{"settings": {"number_of_shards": 2,"number_of_replicas": 0},"mappings": {"_routing": {"required": true}}
}

很多时候自定义路由是为了减少查询时扫描shard的个数,从而提高查询效率。默认查询接口会搜索所有的shard,但也可以指定routing字段,这样就只会查询routing计算出来的shard,提高查询速度。

使用方式也非常简单,只需在查询语句上面指定routing即可,允许指定多个:

GET study_route/_search?routing=key1&filter_path=hits
{"query": {"match": {"data": "b"}}
}{"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.86312973,"hits" : [{"_index" : "study_route","_type" : "_doc","_id" : "b","_score" : 0.86312973,"_routing" : "key1","_source" : {"data" : "B with routing key1"}}]}
}

Elasticsearch之路由相关推荐

  1. Elasticsearch的路由(Routing)特性

    Elasticsearch路由机制介绍 Elasticsearch的路由机制与其分片机制有着直接的关系.Elasticsearch的路由机制即是通过哈希算法,将具有相同哈希值的文档放置到同一个主分片中 ...

  2. Elasticsearch:路由 - routing

    你是否考虑过 Elasticsearch 如何知道将文档存储在何处? 它如何知道在哪里寻找它们,以及是否检索.更新或删除它们? 这是一个令人兴奋的过程,一切都归结为路由的概念. 路由介绍 路由是确定文 ...

  3. elasticsearch Routing 路由详解

    前言 当索引一个文档的时候,文档会被存储到一个主分片中.那么,elasticsearch如何知道一个文档应该存放到哪个分片中呢? 首先这肯定不是随机的,否则在检索文档时就不知道该从哪去寻找它了.实际上 ...

  4. 【elasticsearch】 elasticsearch document 路由 (routing) 到shard

    文章目录 1.概述 2. 工作原理 2.1.数据路由(routing) 2.2.路由算法 2.3 routing_partition_size参数 3.primary shard数量不可变的谜底 4. ...

  5. 【elasticsearch】 es 路由错误 不到 也可能 查询到的分析

    1.概述 转载:关于elasticSearch中路由的一些问题 路由相关的解读请参考:[elasticsearch] elasticsearch document 路由 (routing) 到shar ...

  6. elasticsearch常见属性单词解释

    一.前言 说实话,刚测试ES的时候,我的内心是崩溃的,好多单词都不知道代表什么意思,只能一边测试,一边查询.看到就赶紧记下来,一天下来,也算是学的七七八八吧.这里分享给大家. 二.ES常见单词解释 1 ...

  7. ElasticSearch index 剖析

    ElasticSearch index 剖析 在看ElasticSearch权威指南基础入门中关于:分片内部原理这一小节内容后,大致对ElasticSearch的索引.搜索底层实现有了一个初步的认识. ...

  8. es查询大文本效率_进一步提高Elasticsearch的检索效率

    Elasticsearch的路由机制与其分片机制有着直接的关系.Elasticsearch的路由机制即是通过哈希算法,将具有相同哈希值的文档放置到同一个主分片中.这个和通过哈希算法来进行负载均衡几乎是 ...

  9. Elasticsearch 索引别名应用

    Elasticsearch 索引别名应用 Elasticsearch支持给索引增加别名,即可以给一个或多个索引增加一个别名.后续查询自动转换别名为实际索引名称.别名也可以和过滤器一起使用实现类似与视图 ...

最新文章

  1. Cheat—— 给Linux初学者和管理员一个终极命令行备忘单
  2. java string s_Java字符串:“String s=新字符串(”愚蠢“);
  3. eclipse如何导出WAR包
  4. Linux(Ubuntu14.04)下安装Anaconda和Spyder
  5. date时区 es logstash_es-日志存储-Logstash 介绍
  6. es6 --- 使用node的memoryUsage检测WeakMap()
  7. postgresql 高可用 etcd + patroni 之六 callback bind vip
  8. 基于RANSAC的激光点云分割
  9. 背景图片的位置(HTML、CSS)
  10. 一个node系统的日志管理
  11. 微信语音技术原理_微信语音多群直播原理-一起学堂
  12. 智慧办公室空间管理系统方案优点
  13. Android应用测试篇
  14. html excel零不显示,Excel中把0显示为空白的三种解决方法
  15. 怎么自费出书方法步骤
  16. 计算机Excel运行环境,Excel2007免费完整版 最新电脑版
  17. 如何显示Word 左侧目录
  18. C语言 数据结构 栈的线性实现 基本操作代码
  19. 局域网oracle 速度慢,[转帖]局域网中其他用户感觉上网速度慢、网速卡
  20. C++ 学习笔记(22) Builder Pattern

热门文章

  1. 有心栽花花不开,无心插柳柳成荫
  2. 如何查询快递信息,教你一招高效查找包裹物流
  3. CAD文件如何在线转换成JPG格式
  4. Test Case Design Method - OATS
  5. 25匹马,5条赛道,一匹马一个赛道,求决胜1,2,3名至少多少场。
  6. tyvj 1031 热浪
  7. 【计算机物理模拟】-力矩、转动惯量和角速度之间的关系
  8. 医美“非标化”埋雷 新氧科技流量变现受制约
  9. 【心电检测】基于 EMD、CEEMDAN 算法实现呼吸心跳信号检测实例(去除呼吸旁瓣干扰,测量心跳频率)附matlab代码
  10. Word快捷键大全 Word2013/2010/2007/2003常用快捷键大全