当前位置: > > > Elasticsearch - routing路由功能使用详解(实现极速查询)

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)然后调用 ElasticsearchAPI 接口初始化一些数据,注意这里我们使用了 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");
  • 结果如下:

(3)我们把 routing 参数修改一下,改为 class2
// 创建查询请求
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("rout");
//指定路由参数
searchRequest.routing("class2");
  • 此时结果如下:
评论0