es的调优

3.1、分片查询方式

当前的图片中有5个主分片,5个副本;这对于es的集群来说,这种配置是非常常见的;

但是问题来了,当我们的客户端做查询的时候,程序会向主分片发送请求还是副本发送请求?

还是说直接去集群上随机找一台机器查询,还是在这个机器里面在随机的找到分片和副本查询?

【注意】:

默认情况下是随机查询的

这种随机的方式其实效率并不高,

1查询阶段

(1):客户端发送一个检索请求给node3,此时node3会创建一个空的优先级队列并且配置好分页参数from与size

(2):node3将检所请求发送给index中的每一个shard(primary 和 replica),每一个在本地执行检索,并将结果添加到本地的优先级队列中;

(3):每个shard返回本地优先级序列中所记录的_id与score值,并发送node3。Node3将这些值合并到自己的本地的优先级队列中,并做全局的排序。

 

2获取阶段

(1):node 3获取了所有待检索数据的定位之后,发送一个mget的请求给与数据相关的shard。

(2):每个收到node 3的get请求的shard将读取相关文档_source中的内容,并将它们返回给node 3。

(3):当node 3获取到了所有shard返回的文档后,node 3将它们合并成一条汇总的结果,返回给客户端。

我们通过上面的查询方式可以了解到,如果我们直接将客户端定位到指定的机器上查询,就少去了中间的来回复制的步骤,这样在检索大量数据的时候,网络的IO也得到了提升

其实,在elasticsearch的查询阶段,我们可以做很多的优化措施,比如控制我们的分片查询方式:

Es会将数据均衡的存储在分片中,我们可以指定es去具体的分片或节点中查询从而进一步的实现es极速查询。

1:randomizeacross shards
随机选择分片查询数据,es的默认方式

2:_local
优先在本地节点上的分片查询数据然后再去其他节点上的分片查询,本地节点可以减少跨网络的IO问题,但有可能造成负载不均问题

3:_primary
只在主分片中查询不去副本查

4:_primary_first
优先在主分片中查,如果主分片挂了则去副本查

5:_only_node[已经被移除]
只在指定id的节点中的分片中查询

6:_prefer_node
优先在指定你给节点中查询

7:_shards
在指定分片中查询

8:_only_nodes
可以自定义去指定的多个节点查询,es不提供此方式需要改源码。
  /**
     * 分片查询方式
     * */
    @Test
    public void searchType(){
        SearchRequestBuilder builder = client.prepareSearch("school").setTypes("student");
        SearchResponse searchResponse = builder.setQuery(QueryBuilders.matchQuery("name", "于谦"))
//                .setPreference("_local")
//                .setPreference("_primary")
//                .setPreference("_only_nodes:*")
//               .setPreference("_prefer_nodes:jnrN6IYURTKYPE_ZYQqFDg")
//                .setPreference("_shards:0,1,2")//TODO 可以提高查询效率
//                .setPreference("randomizeacross")
                .get();//指定查询方式
        SearchHits hits = searchResponse.getHits();
        System.out.println("查询的结果数量有"+hits.getTotalHits()+"条");
        System.out.println("结果中最高分:"+hits.getMaxScore());

        // 遍历每条数据
        Iterator<SearchHit> iterator = hits.iterator();
        while(iterator.hasNext()){
            SearchHit searchHit = iterator.next();
            System.out.println("所有的数据JSON的数据格式:"+searchHit.getSourceAsString());
            System.out.println("每条得分:"+searchHit.getScore());
            // 获取每个字段的数据
            System.out.println("id:"+searchHit.getSource().get("id"));
            System.out.println("name:"+searchHit.getSource().get("name"));
            System.out.println("age:"+searchHit.getSource().get("age"));
            System.out.println("**********************************************");
            for(Iterator<SearchHitField> ite = searchHit.iterator(); ite.hasNext();){
                SearchHitField next = ite.next();
                System.out.println(next.getValues());
            }
        }
    }

 

posted @ 2017-05-22 23:47  niutao  阅读(1066)  评论(0编辑  收藏  举报