Elasticsearch - routing路由功能使用详解(实现极速查询)
1,基本介绍
(1)Elasticsearch 在添加数据时,会根据 id 或者 routing 参数进行 hash,得到 hash 值再与该索引库的分片数量取模,得到的值即为存入的分片编号。
(2)如果多条数据使用相同的 routing,则最终计算出来的分片编号都是一样的,那么这些数据就可以存储到相同的分片里面了。
(3)后期查询时只需要到指定分片中查询即可,可以显著提高查询性能。
提示:如果在面试的时候面试官问你如何在 ES 中实现极速查询,其实就是问这个 routing 路由功能的。
2,存储数据时使用路由参数
(1)首先,我们执行如下命令创建一个新的索引库,指定 5 个分片,0 个副本。
curl -H "Content-Type: application/json" \ -XPUT 'http://192.168.121.128:9200/rout/' \ -d '{ "settings": { "number_of_shards": 5, "number_of_replicas": 0 } }'
(2)然后调用 Elasticsearch 的 API 接口初始化一些数据,注意这里我们使用了 routing 参数:
curl -H "Content-Type: application/json" -XPOST 'http://192.168.121.128:9200/rout/_doc/1?routing=class1' -d'{"name":"tom","age":18}' curl -H "Content-Type: application/json" -XPOST 'http://192.168.121.128:9200/rout/_doc/2?routing=class1' -d'{"name":"jack","age":29}' curl -H "Content-Type: application/json" -XPOST 'http://192.168.121.128:9200/rout/_doc/3?routing=class1' -d'{"name":"jessica","age":18}' curl -H "Content-Type: application/json" -XPOST 'http://192.168.121.128:9200/rout/_doc/4?routing=class1' -d'{"name":"dave","age":19}' curl -H "Content-Type: application/json" -XPOST 'http://192.168.121.128:9200/rout/_doc/5?routing=class1' -d'{"name":"lilei","age":18}' curl -H "Content-Type: application/json" -XPOST 'http://192.168.121.128:9200/rout/_doc/6?routing=class1' -d'{"name":"lili","age":29}'
- 如果是使用的 JavaAPI,那么需要通过使用 routing 函数指定。
private static void addIndexByJson(RestHighLevelClient client) throws IOException { IndexRequest request = new IndexRequest("emp"); request.id("10"); String jsonString = "{" + "\"name\":\"jessic\"," + "\"age\":20" + "}"; request.source(jsonString, XContentType.JSON); request.routing("class1"); //执行 client.index(request, RequestOptions.DEFAULT); }
(3)查看数据在分片中的分布情况,发现所有数据都在 0 号分片里面,说明 routing 参数生效了。
curl -XGET 'http://192.168.121.128:9200/_cat/shards/rout?v'

(4)通过代码查询的时候,可以通过偏好查询指定只查询 0 号分片里面的数据。
//获取RestClient连接 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("192.168.121.128", 9200, "http"), new HttpHost("192.168.121.129", 9200, "http"), new HttpHost("192.168.121.130", 9200, "http"))); // 创建查询请求 SearchRequest searchRequest = new SearchRequest(); searchRequest.indices("rout"); //指定分片查询方式 searchRequest.preference("_shards:0"); // 执行查询操作 SearchResponse searchResponse =client.search(searchRequest,RequestOptions.DEFAULT); // 获取查询返回的结果 SearchHits hits =searchResponse.getHits(); // 获取数据总数 long numHits = hits.getTotalHits().value; System.out.println("数据总数:"+numHits); // 获取具体内容 SearchHit[] searchHits =hits.getHits(); // 迭代解析具体内容 for(SearchHit hit : searchHits) { String sourceAsString = hit.getSourceAsString(); System.out.println(sourceAsString); } //关闭连接 client.close();
- 这样就可以查看所有的数据:

3,查询数据时使用路由参数
(1)上面样例中时通过偏好查询中的 _shard 手工指定分片编号在使用的时候不太友好,需要我们单独维护一份数据和分片之间的关系,比较麻烦。
(2)还有一种比较简单常用的方式是在查询的时候设置相同的路由参数,这样就可以快速查询到使用这个路由参数添加的数据了。
提示:底层其实是会计算这个路由参数对应的分片编号,最终到指定的分片中查询数据。
// 创建查询请求 SearchRequest searchRequest = new SearchRequest(); searchRequest.indices("rout"); //指定路由参数 searchRequest.routing("class1");
- 结果如下:

// 创建查询请求 SearchRequest searchRequest = new SearchRequest(); searchRequest.indices("rout"); //指定路由参数 searchRequest.routing("class2");
- 此时结果如下:
