赞
踩
什么是ElasticSearch路由?
elasticsearch的路由机制决定一个文档存储到索引的哪一个分片上,即文档到分片的路由,公式如下:
shard_num = hash(_routing) % num_shards
上面的_routing默认指的是文档ID,如果想要修改这个默认值,只需要在插入数据的时候指定路由的key即可
- // 1、创建索引 2分片0副本
- PUT route_test/
- {
- "settings": {
- "number_of_shards": 2,
- "number_of_replicas": 0
- }
- }
-
- // 2、查看各分片信息
- GET _cat/shards/route_test?v
- index shard prirep state docs store ip node
- route_test 1 p STARTED 0 230b 172.17.0.1 fuE-zT9
- route_test 0 p STARTED 0 230b 172.17.0.1 fuE-zT9
-
- // 3、插入第一条数据 a
- PUT route_test/_doc/a?refresh
- {
- "data": "A"
- }
-
- // 4、此时再看各分片信息
- index shard prirep state docs store ip node
- route_test 1 p STARTED 0 261b 172.17.0.1 fuE-zT9
- route_test 0 p STARTED 1 3.3kb 172.17.0.1 fuE-zT9
-
- // 5、插入第二条数据 b
- PUT route_test/_doc/b?refresh
- {
- "data": "B"
- }
-
- // 6、此时再看各分片信息
- index shard prirep state docs store ip node
- route_test 1 p STARTED 1 3.3kb 172.17.0.1 fuE-zT9
- route_test 0 p STARTED 1 3.3kb 172.17.0.1 fuE-zT9
-
- // 7、查看该索引下的数据
- GET route_test/_search
- {
- "took": 1,
- "timed_out": false,
- "_shards": {
- "total": 2,
- "successful": 2,
- "skipped": 0,
- "failed": 0
- },
- "hits": {
- "total": 2,
- "max_score": 1.0,
- "hits": [
- {
- "_index": "route_test",
- "_type": "_doc",
- "_id": "a",
- "_score": 1.0,
- "_source": {
- "data": "A"
- }
- },
- {
- "_index": "route_test",
- "_type": "_doc",
- "_id": "b",
- "_score": 1.0,
- "_source": {
- "data": "B"
- }
- }
- ]
- }
- }
上面的例子解释一下:
先是创建了一个2分片0副本的索引,然后往里面插了两条数据a和b,文档a进入了编号为0的分片,文档b进入了编号为1的分片
- // 8、插入第三条数据 指定路由值key1
- PUT route_test/_doc/c?routing=key1&refresh
- {
- "data": "C"
- }
-
- // 9、查看分片信息 可以看出c进到了编号为1的分片 也就是说key1路由对应编号1分片
- index shard prirep state docs store ip node
- route_test 1 p STARTED 2 6.8kb 172.17.0.1 fuE-zT9
- route_test 0 p STARTED 1 3.4kb 172.17.0.1 fuE-zT9
这次带着路由值来插入数据c,路由值为key1,通过上面的结果,可以看出key1路由对应着编号为1的分片
更有意思的来了,之前已经入库的数据 a和b 我现在想要再让他们带着路由入一次库
- // 步骤11:插入 docid=a 的数据,并指定 routing=key1
- PUT route_test/_doc/a?routing=key1&refresh
- {
- "data": "A with routing key1"
- }
-
- // es返回信息
- {
- "_index": "route_test",
- "_type": "_doc",
- "_id": "a",
- "_version": 1,
- "result": "created", // 注意这里是created,因为文档a之前没有在分片1里面出现过
- "forced_refresh": true,
- "_shards": {
- "total": 1,
- "successful": 1,
- "failed": 0
- },
- "_seq_no": 2,
- "_primary_term": 1
- }
这时就有问题了,一个索引里竟然有两个相同ID的文档,分片0里面出现了一次,分片1里面竟然又出现了一次
可以总结出一个规律:ES索引中的ID唯一性是由路由来保证的,我们修改并打破了默认的路由规则,就产生了一些问题,ID不再唯一了
- // 步骤12 插入文档b 路由值仍然为key1
- PUT route_test/_doc/b?routing=key1&refresh
- {
- "data": "B with routing key1"
- }
-
- // ES返回结果
- {
- "_index": "route_test",
- "_type": "_doc",
- "_id": "b",
- "_version": 2,
- "result": "updated", // 因为分片1之前就有文档b,你又插入了一次,这次就是更新了,没毛病
- "forced_refresh": true,
- "_shards": {
- "total": 1,
- "successful": 1,
- "failed": 0
- },
- "_seq_no": 3,
- "_primary_term": 1
- }
-
- // 步骤13 查看分片信息
- index shard prirep state docs store ip node
- route_test 1 p STARTED 3 10.7kb 172.17.0.1 fuE-zT9
- route_test 0 p STARTED 1 3.4kb 172.17.0.1 fuE-zT9
- 此时分片0里面的数据:a
- 此时分片1里面的数据:b c a
ES shard的实质是Lucene的索引,所以其实每个shard都是一个功能完善的倒排索引。ES能保证docid全局唯一是采用do id作为了路由,所以同样的docid肯定会路由到同一个shard上面,如果出现docid重复,就会update或者抛异常,从而保证了集群内docid唯一标识一个doc。但如果我们换用其它值做routing,那这个就保证不了了,如果用户还需要docid的全局唯一性,那只能自己保证了。
很多时候自定义路由是为了减少查询时扫描shard的个数,从而提高查询效率。默认查询接口会搜索所有的shard,但也可以指定routing字段,这样就只会查询routing计算出来的shard,提高查询速度。使用方式也非常简单,只需在查询语句上面指定routing即可,允许指定多个
- GET route_test/_search?routing=key1,key2
- {
- "query": {
- "match": {
- "data": "b"
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。