elasticsearch 排序scroll 分页能排序吗

Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回。那么,如果要实现分页查询该怎么办呢?
更多内容参考Elasticsearch资料汇总
按照一般的查询流程来说,如果我想查询前10条数据:
1 客户端请求发给某个节点
2 节点转发给个个分片,查询每个分片上的前10条
3 结果返回给节点,整合数据,提取前10条
4 返回给请求客户端
那么当我想要查询第10条到第20条的数据该怎么办呢?这个时候就用到分页查询了。
from-size&浅&分页
&浅&分页的概念是小博主自己定义的,可以理解为简单意义上的分页。它的原理很简单,就是查询前20条数据,然后截断前10条,只返回10-20的数据。这样其实白白浪费了前10条的查询。
查询的方法如:
&from& : 0, &size& : 10,
&query& : {
&term& : { &user& : &kimchy& }
其中,from定义了目标数据的偏移值,size定义当前返回的事件数目。
默认from为0,size为10,即所有的查询默认仅仅返回前10条数据。
做过测试,越往后的分页,执行的效率越低。
通过下图可以看出,刨去一些异常的数据,总体上还是会随着from的增加,消耗时间也会增加。而且数据量越大,效果越明显!
也就是说,分页的偏移值越大,执行分页查询时间就会越长!
scroll“深”分页
相对于from和size的分页来说,使用scroll可以模拟一个传统数据的游标,记录当前读取的文档信息位置。这个分页的用法,不是为了实时查询数据,而是为了一次性查询大量的数据(甚至是全部的数据)。
因为这个scroll相当于维护了一份当前索引段的快照信息,这个快照信息是你执行这个scroll查询时的快照。在这个查询后的任何新索引进来的数据,都不会在这个快照中查询到。但是它相对于from和size,不是查询所有数据然后剔除不要的部分,而是记录一个读取的位置,保证下一次快速继续读取。
API使用方法如:
curl -XGET 'localhost:9200/twitter/tweet/_search?scroll=1m' -d '
&query&: {
&match& : {
&title& : &elasticsearch&
会自动返回一个_scroll_id,通过这个id可以继续查询(实际上这个ID会很长哦!):
curl -XGET
'localhost:9200/_search/scroll?scroll=1m&scroll_id=c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1'
注意,我在使用1.4版本的ES时,只支持把参数放在URL路径里面,不支持在JSON body中使用。
有个很有意思的事情,细心的会发现,这个ID其实是通过base64编码的:
cXVlcnlUaGVuRmV0Y2g7MTY7MjI3NTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzQ6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgwOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4MTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODM6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgyOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg5OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4NDp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODU6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjc4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3OTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzA7
如果使用解码工具可以看到:
queryThenF16;2275:vtXKJ8lnQImdiwcDtPT-kA;2274:vtXKJ8lnQImdiwcDtPT-kA;2280:vtXKJ8lnQImdiwcDtPT-kA;2281:vtXKJ8lnQImdiwcDtPT-kA;2283:vtXKJ8lnQImdiwcDtPT-kA;2282:vtXKJ8lnQImdiwcDtPT-kA;2286:vtXKJ8lnQImdiwcDtPT-kA;2287:vtXKJ8lnQImdiwcDtPT-kA;2289:vtXKJ8lnQImdiwcDtPT-kA;2284:vtXKJ8lnQImdiwcDtPT-kA;2285:vtXKJ8lnQImdiwcDtPT-kA;2288:vtXKJ8lnQImdiwcDtPT-kA;2276:vtXKJ8lnQImdiwcDtPT-kA;2277:vtXKJ8lnQImdiwcDtPT-kA;2278:vtXKJ8lnQImdiwcDtPT-kA;2279:vtXKJ8lnQImdiwcDtPT-kA;0;
虽然搞不清楚里面是什么内容,但是看到了一堆规则的键值对,总是让人兴奋一下!
测试from&size VS scroll的性能
首先呢,需要在java中引入elasticsearch-jar,比如使用maven:
&dependency&
&groupId&org.elasticsearch&/groupId&
&artifactId&elasticsearch&/artifactId&
&version&1.4.4&/version&
&/dependency&
然后初始化一个client对象:
private static TransportC
private static String INDEX = &index_name&;
private static String TYPE = &type_name&;
public static TransportClient init(){
Settings settings = ImmutableSettings.settingsBuilder()
.put(&client.transport.sniff&, true)
.put(&cluster.name&, &cluster_name&)
client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress(&localhost&,9300));
public static void main(String[] args) {
TransportClient client = init();
//这样就可以使用client执行查询了
然后就是创建两个查询过程了 ,下面是from-size分页的执行代码:
System.out.println(&from size 模式启动!&);
Date begin = new Date();
long count = client.prepareCount(INDEX).setTypes(TYPE).execute().actionGet().getCount();
SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX).setTypes(TYPE).setQuery(QueryBuilders.matchAllQuery());
for(int i=0,sum=0; sum& i++){
SearchResponse response = requestBuilder.setFrom(i).setSize(50000).execute().actionGet();
sum += response.getHits().hits().
System.out.println(&总量&+count+& 已经查到&+sum);
Date end = new Date();
System.out.println(&耗时: &+(end.getTime()-begin.getTime()));
下面是scroll分页的执行代码,注意啊!scroll里面的size是相对于每个分片来说的,所以实际返回的数量是:分片的数量*size
System.out.println(&scroll 模式启动!&);
begin = new Date();
SearchResponse scrollResponse = client.prepareSearch(INDEX)
.setSearchType(SearchType.SCAN).setSize(10000).setScroll(TimeValue.timeValueMinutes(1))
.execute().actionGet();
count = scrollResponse.getHits().getTotalHits();//第一次不返回数据
for(int i=0,sum=0; sum& i++){
scrollResponse = client.prepareSearchScroll(scrollResponse.getScrollId())
.setScroll(TimeValue.timeValueMinutes(8))
.execute().actionGet();
sum += scrollResponse.getHits().hits().
System.out.println(&总量&+count+& 已经查到&+sum);
end = new Date();
System.out.println(&耗时: &+(end.getTime()-begin.getTime()));
我这里总的数据有33万多,分别以每页,50000的数据量请求,得到如下的执行时间:
可以看到仅仅30万,就相差接近一倍的性能,更何况是如今的大数据环境...因此,如果想要对全量数据进行操作,快换掉fromsize,使用scroll吧!Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回。那么,如果要实现分页查询该怎么办呢?
更多内容参考
按照一般的查询流程来说,如果我想查询前10条数据:
1 客户端请求发给某个节点
2 节点转发给个个分片,查询每个分片上的前10条
3 结果返回给节点,整合数据,提取前10条
4 返回给请求客户端
那么当我想要查询第10条到第20条的数据该怎么办呢?这个时候就用到分页查询了。
from-size&浅&分页
&浅&分页的概念是小博主自己定义的,可以理解为简单意义上的分页。它的原理很简单,就是查询前20条数据,然后截断前10条,只返回10-20的数据。这样其实白白浪费了前10条的查询。
查询的方法如:
&from& : 0, &size& : 10,
&query& : {
&term& : { &user& : &kimchy& }
其中,from定义了目标数据的偏移值,size定义当前返回的事件数目。
默认from为0,size为10,即所有的查询默认仅仅返回前10条数据。
做过测试,越往后的分页,执行的效率越低。
通过下图可以看出,刨去一些异常的数据,总体上还是会随着from的增加,消耗时间也会增加。而且数据量越大,效果越明显!
也就是说,分页的偏移值越大,执行分页查询时间就会越长!
scroll“深”分页
相对于from和size的分页来说,使用scroll可以模拟一个传统数据的游标,记录当前读取的文档信息位置。这个分页的用法,不是为了实时查询数据,而是为了一次性查询大量的数据(甚至是全部的数据)。
因为这个scroll相当于维护了一份当前索引段的快照信息,这个快照信息是你执行这个scroll查询时的快照。在这个查询后的任何新索引进来的数据,都不会在这个快照中查询到。但是它相对于from和size,不是查询所有数据然后剔除不要的部分,而是记录一个读取的位置,保证下一次快速继续读取。
API使用方法如:
curl -XGET 'localhost:9200/twitter/tweet/_search?scroll=1m' -d '
&query&: {
&match& : {
&title& : &elasticsearch&
会自动返回一个_scroll_id,通过这个id可以继续查询(实际上这个ID会很长哦!):
curl -XGET
'localhost:9200/_search/scroll?scroll=1m&scroll_id=c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1'
注意,我在使用1.4版本的ES时,只支持把参数放在URL路径里面,不支持在JSON body中使用。
有个很有意思的事情,细心的会发现,这个ID其实是通过base64编码的:
cXVlcnlUaGVuRmV0Y2g7MTY7MjI3NTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzQ6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgwOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4MTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODM6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjgyOnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg5OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI4NDp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyODU6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjg4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3Njp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzIyNzc6dnRYS0o4bG5RSW1kaXdjRHRQVC1rQTsyMjc4OnZ0WEtKOGxuUUltZGl3Y0R0UFQta0E7MjI3OTp2dFhLSjhsblFJbWRpd2NEdFBULWtBOzA7
如果使用解码工具可以看到:
queryThenF16;2275:vtXKJ8lnQImdiwcDtPT-kA;2274:vtXKJ8lnQImdiwcDtPT-kA;2280:vtXKJ8lnQImdiwcDtPT-kA;2281:vtXKJ8lnQImdiwcDtPT-kA;2283:vtXKJ8lnQImdiwcDtPT-kA;2282:vtXKJ8lnQImdiwcDtPT-kA;2286:vtXKJ8lnQImdiwcDtPT-kA;2287:vtXKJ8lnQImdiwcDtPT-kA;2289:vtXKJ8lnQImdiwcDtPT-kA;2284:vtXKJ8lnQImdiwcDtPT-kA;2285:vtXKJ8lnQImdiwcDtPT-kA;2288:vtXKJ8lnQImdiwcDtPT-kA;2276:vtXKJ8lnQImdiwcDtPT-kA;2277:vtXKJ8lnQImdiwcDtPT-kA;2278:vtXKJ8lnQImdiwcDtPT-kA;2279:vtXKJ8lnQImdiwcDtPT-kA;0;
虽然搞不清楚里面是什么内容,但是看到了一堆规则的键值对,总是让人兴奋一下!
测试from&size VS scroll的性能
首先呢,需要在java中引入elasticsearch-jar,比如使用maven:
&dependency&
&groupId&org.elasticsearch&/groupId&
&artifactId&elasticsearch&/artifactId&
&version&1.4.4&/version&
&/dependency&
然后初始化一个client对象:
private static TransportC
private static String INDEX = &index_name&;
private static String TYPE = &type_name&;
public static TransportClient init(){
Settings settings = ImmutableSettings.settingsBuilder()
.put(&client.transport.sniff&, true)
.put(&cluster.name&, &cluster_name&)
client = new TransportClient(settings).addTransportAddress(new InetSocketTransportAddress(&localhost&,9300));
public static void main(String[] args) {
TransportClient client = init();
//这样就可以使用client执行查询了
然后就是创建两个查询过程了 ,下面是from-size分页的执行代码:
System.out.println(&from size 模式启动!&);
Date begin = new Date();
long count = client.prepareCount(INDEX).setTypes(TYPE).execute().actionGet().getCount();
SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX).setTypes(TYPE).setQuery(QueryBuilders.matchAllQuery());
for(int i=0,sum=0; sum& i++){
SearchResponse response = requestBuilder.setFrom(i).setSize(50000).execute().actionGet();
sum += response.getHits().hits().
System.out.println(&总量&+count+& 已经查到&+sum);
Date end = new Date();
System.out.println(&耗时: &+(end.getTime()-begin.getTime()));
下面是scroll分页的执行代码,注意啊!scroll里面的size是相对于每个分片来说的,所以实际返回的数量是:分片的数量*size
System.out.println(&scroll 模式启动!&);
begin = new Date();
SearchResponse scrollResponse = client.prepareSearch(INDEX)
.setSearchType(SearchType.SCAN).setSize(10000).setScroll(TimeValue.timeValueMinutes(1))
.execute().actionGet();
count = scrollResponse.getHits().getTotalHits();//第一次不返回数据
for(int i=0,sum=0; sum& i++){
scrollResponse = client.prepareSearchScroll(scrollResponse.getScrollId())
.setScroll(TimeValue.timeValueMinutes(8))
.execute().actionGet();
sum += scrollResponse.getHits().hits().
System.out.println(&总量&+count+& 已经查到&+sum);
end = new Date();
System.out.println(&耗时: &+(end.getTime()-begin.getTime()));
我这里总的数据有33万多,分别以每页,50000的数据量请求,得到如下的执行时间:
可以看到仅仅30万,就相差接近一倍的性能,更何况是如今的大数据环境...因此,如果想要对全量数据进行操作,快换掉fromsize,使用scroll吧!
阅读(...) 评论()在Elasticsearch中,一次查询只能得到一次独立的结果,在分页中这是很不方便的,当用Elasticsearch进行第n页查询的时候,Elasticsearch内部是查询了从n页的所有数据,只是在返回的时候抛弃了前面的n-1页的内容。这样对查询一个大量数据的时候是非常不方便的。但Elasticsearch提供了滚动API来解决此问题,这有点像数据库中的游标。
& & 在Elasticsearch中,一次查询只能得到一次独立的结果,在分页中这是很不方便的,当用Elasticsearch进行第n页查询的时候,Elasticsearch内部是查询了从n页的所有数据,只是在返回的时候抛弃了前面的n-1页的内容。这样对查询一个大量数据的时候是非常不方便的。但Elasticsearch提供了滚动API来解决此问题,这有点像数据库中的游标。
滚动查询请求
& & 滚动是不适合实时用户请求,而是适合处理大量的数据,例如为了重建一个索引到一个新的索引中。
& & 官方客户端只支持Perl和Python。
& & 注意:从 scroll 请求返回的结果反映了在查询发生时刻的索引状态,就像一个快照。后续的对文档的改动(索引、更新或者删除)都只会影响后面的搜索请求。
& & 为了使用 scroll,在第一次搜索请求的查询中指定 scroll 参数,它告诉 Elasticsearch 需要保持搜索的上下文环境多长时间。例如:
请求:POST&http://localhost:9200/secilog/log/_search?scroll=1m&pretty
&&&&"query":&{
&&&&&&&&"term":&{
&&&&&&&&&&&&"message":&"text"
返回的结果:
&&"_scroll_id"&:&"cXVlcnlBbmRGZXRjaDsxOzExMjo1azRqYldqOVJmYTdIdlVWSk94X2FnOzA7",
&&"took"&:&1,
&&"timed_out"&:&false,
&&"_shards"&:&{
&&&&"total"&:&1,
&&&&"successful"&:&1,
&&&&"failed"&:&0
&&"hits"&:&{
&&&&"total"&:&1,
&&&&"max_score"&:&0.4232868,
&&&&"hits"&:&[&{
&&&&&&"_index"&:&"secilog",
&&&&&&"_type"&:&"log",
&&&&&&"_id"&:&"10",
&&&&&&"_score"&:&0.4232868,
&&&&&&"_source"&:&{
&&&&&&&&"type"&:&"file",
&&&&&&&&"message"&:&"secilog&is&a&log&real-time&analyse&software,it's&full&text&search&is&based&on&Elasticsearch&"
&&&&从返回值中可以看出上面的请求结果中包含一个 scroll_id,这个 ID 可以被传递给 scroll API 来检索下一个批次的内容。在下一次查询中的实例:
请求:POST&http://localhost:9200/_search/scroll?pretty
&&&"scroll"&:&"1m",&
&&&"scroll_id"&:&"cXVlcnlBbmRGZXRjaDsxOzExMjo1azRqYldqOVJmYTdIdlVWSk94X2FnOzA7"
返回的结果:
&&"_scroll_id"&:&"cXVlcnlBbmRGZXRjaDsxOzExMzo1azRqYldqOVJmYTdIdlVWSk94X2FnOzA7",
&&"took"&:&1,
&&"timed_out"&:&false,
&&"_shards"&:&{
&&&&"total"&:&1,
&&&&"successful"&:&1,
&&&&"failed"&:&0
&&"hits"&:&{
&&&&"total"&:&1,
&&&&"max_score"&:&0.4232868,
&&&&"hits"&:&[&]
&&&&每一次调用scroll查询返回下一批的结果,直到返回为空("hits" : [ ]),表示查询完成。
注意:第一次搜索请求和每个后续的滚动请求返回一个新的 _scroll_id,只有最新的 _scroll_id 才能被使用。
如果请求指定了聚合(aggregation),只有第一次搜索的返回结果才会包含聚合结果。
当使用_doc排序查询的时候,滚动的效率是最高的,当你向遍历所有的文档,且无顺序要求,这是效率最高的方式:
请求:POST&localhost:9200/_search?scroll=1m
&&"sort":&[
&&&&"_doc"
搜索的时效性
&&&&滚动scroll&参数告诉Elasticsearch应保持多长时间的搜索。这个值并不需要长到可以处理所有的数据,只要够处理前一批次结果的时间。每一个滚动请求设置一个新的有效时间。
&&&&一般来说,合并过程优化的背景是通过合并小段来创建一个新的大段来优化索引,然后删除小段。在执行滚动期间仍可以进行索引优化,但在打开搜索上下文时当小段仍然在使用候的时候会阻止小段的删除。这就是为什么后来对文档的改变不会影响滚动搜索请求的结果。
提示:保持较旧的段,意味着需要更多的文件句柄。确保在节点中已配置访问文件句柄的参数足够用。
你可以通过stats API检查打开了多少搜索上下文。
请求:GET&http://localhost:9200/_nodes/stats/indices/search?pretty
清除滚动接口
&&&&当滚动超时的时候会自动删除搜索上下文,然而保持滚动打开会产生成本,所以 scrolls 当scroll不再被使用的时候需要用 clear-scroll 显式地清除。
请求:DELETE localhost:9200/_search/scroll
&&&&"scroll_id"&:&["cXVlcnlBbmRGZXRjaDsxOzExMzo1azRqYldqOVJmYTdIdlVWSk94X2FnOzA7"]
可以同时清除多个id
&&&&"scroll_id"&:&["cXVlcnlBbmRGZXRjaDsxOzExMzo1azRqYldqOVJmYTdIdlVWSk94X2FnOzA7","qYldqOVJmYTdIdl"]
或者使用_all参数清除所有id
DELETE localhost:9200/_search/scroll/_all
& & 赛克蓝德(secisland)后续会逐步对Elasticsearch的最新版本的各项功能进行分析,近请期待。也欢迎加入secisland公众号进行关注。
& 开源中国(OSChina.NET) |
开源中国社区(OSChina.net)是工信部
指定的官方社区Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回。那么,如果要实现分页查询该怎么办呢?按照一般的查询流程来说,如果我想查询前10条数据:1 客户端请求发给某个节点2 节点转发给个个分片,查询每个分片上的前10条3 结果返回给节点,整合数据,提取前10条4 返回给请求客户端那么当我想要查询第10条到第20条的数据该怎么办呢?这个时候就用到分页查询了。from-size&浅&分页&浅&分页的概念是小博主自己定义的,可以理解为简单意义上的分页。它的原理很简单,就是查询前20条数据,然后截断前10条,只返回10-20的数据。这样其实白白浪费了前10条的查询。查询的方法如:{
&from& : 0, &size& : 10,
&query& : {
&term& : { &user& : &kimchy& }
}其中,from定义了目标数据的偏移值,size定义当前返回的事件数目。
默认from为0,size为10,即所有的查询默认仅仅返回前10条数据。做过测试,越往后的分页,执行的效率越低。
通过下图可以看出,刨去一些异常的数据,总体上还是会随着from的增加,消耗时间也会增加。而且数据量越大,效果越明显!也就是说,分页的偏移值越大,执行分页查询时间就会越长!scroll“深”分页相对于from和size的分页来说,使用scroll可以模拟一个传统数据的游标,记录当前读取的文档信息位置。这个分页的用法,不是为了实时查询数据,而是为了一次性查询大量的数据(甚至是全部的数据)。因为这个scroll相当于维护了一份当前索引段的快照信息,这个快照信息是你执行这个scroll查询时的快照。在这个查询后的任何新索引进来的数据,都不会在这个快照中查询到。但是它相对于from和size,不是查询所有数据然后剔除不要的部分,而是记录一个读取的位置,保证下一次快速继续读取。API使用方法如:curl -XGET 'localhost:9200/twitter/tweet/_search?scroll=1m' -d '
&query&: {
&match& : {
&title& : &elasticsearch&
'会自动返回一个_scroll_id,通过这个id可以继续查询(实际上这个ID会很长哦!):curl -XGET
'localhost:9200/_search/scroll?scroll=1m&scroll_id=c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1'注意,我在使用1.4版本的ES时,只支持把参数放在URL路径里面,不支持在JSON body中使用。有个很有意思的事情,细心的会发现,这个ID其实是通过base64编码的:
上一篇: 下一篇:(词条-相关词数量)
(推荐度-词条-相关词数)

我要回帖

更多关于 elasticsearch 分页 的文章

 

随机推荐