正确遍历ElasticSearch索引

1:ElasticSearch的查询过程html

2:由ES查询模式引发的深度分页问题java

3:如何正确遍历索引中的数据数据库


 

ElasticSearch的查询过程c#

es的数据查询分两步:安全

第一步是的结果是获取知足查询条件的,分布于各个shard上的_doc_id及对应_score;服务器

第二步是根据第一步获取的全部的_doc_id,去各个shard上获取数据明细,合并返回客户端。elasticsearch

 

在第一步的查询中,es执行了一个相似map-reduce的查询模式:在各个shard上执行一样的查询,获取一样大小的数据(from+size),而后将各个 shard查询结果的_doc_id,_score返回给接收查询请求的节点,最终进行一次汇总。注意这里传输数据的数量是from+size,而不只仅是size大小。ide

 


 

 

由ES查询模式引发的深度分页问题性能

经过ES的查询过程咱们已经能够看出问题,对大数据量的Index进行遍历操做,若是使用from size的方式,将存在极大的资源浪费(由于from过大),固然若是size过大则问题更为严重,服务器内存会被吃光。所以不少站点的查询,都不会容许查看过大的page,深度分页的问题在关系数据库中一样存在。大数据

 


 

 

如何正确遍历索引中的数据

在ES中遍历索引的推荐方式是采用scroll操做,或者在不须要排序而仅仅须要遍历的状况下,能够采用scroll_scan进一步提高性能。

详细可见:Scroll的官方说明

 

简单描述一下Scroll的工做原理:

1:对须要遍历(或获取某个知足条件的子集)的索引,规划一个合理的size做为分页大小;

2:在POST的查询中,增长?scroll=1m(expire time)的query string;

3:在该次查询中,返回结果中除了查询结果之外,还有一个scroll_id(很长),这个scroll_id能够看作是第一次查询时目标索引的快照的游标

4:以后直接在GET请求中将scroll_id做为query string传递,或在POST请求中加入scroll_id便可获取下一批数据,直到没有数据为止,如此实现对全部目标数据的遍历。

(注:在使用scroll遍历的过程当中,不须要再指定各类查询条件好比索引名,size大小什么的,只须要指定scroll_id便可,还能够指定scroll:1m之类的过时时间,相同条件下有效期内的scroll操做,返回的scroll_id是不会变的,仅仅是scroll_id这个游标向前走,返回下一批数据而已)

 

scroll_id能够被显式删除,若是你须要重置对查询目标的遍历过程的话。

 

若是遍历过程不须要对数据进行排序,可使用更为高效的scroll_scan方式进行,以下:

POST ip:port/my_index/my_type/_search?search_type=scan&scroll=1m&size=50
{
    "query": { "match_all": {}}
}

这里须要注意的是,search_type指定为scan,即无需排序,而size=50是指每一个shard上的size是50,最终返回数据是shard*size。

初次之外,scroll_scan与普通的scroll还有以下三点不一样:

  1. Scroll-Scan 结果没有排序,按 index 顺序返回,没有排序,能够提升取数据性能。
  2. 初始化时只返回 _scroll_id,没有具体的 hits 结果
  3. size 控制的是每一个分片的返回的数据量而不是整个请求返回的数据量

 

关于scroll操做是否线程安全的问题,es的客户端(java&c#)均为线程安全,所以我认为经过客户端来进行的scroll请求也是线程安全的。若是有错误请指出。

 

 

 

2016-09-14补充:

 

利用scroll_id获取数据的同时,ES将返回当前查询的scroll_id,在其失效或被删除以前,这个scroll_id都不变,若是但愿程序的可靠性更高,能够用每次返回的scroll_id更新查询POST所发送的scroll_id;同时,对经过scroll_id查询返回的结果集进行判空,以肯定当前scroll_id是否已失效,从而须要从新获取scroll_id。

相关文章
相关标签/搜索