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还有以下三点不一样:
关于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。