Elasticsearch聚合后分页深入详解

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

                       

1、Elasticsearch支持聚合后分页吗,为什么?

不支持,看看Elasticsearch员工如何解读。
这里写图片描述
这里写图片描述
这个问题,2014年在github上有很长的讨论。究其为什么ES不支持聚合后分页?可概括如下:
1)性能角度——聚合分页会在大量的记录中产生性能问题。
2)正确性角度——聚合的文档计数不准确。
所以奇怪的事情可能会发生,如第二页的第一项具有比第一页的最后一个元素更高的计数。

具体为什么会不正确?
这是因为每个分片都提供了自己对有序列表应该是什么的看法,并将这些列表结合起来给出最终的结果值。
举例如下:
对于如下的聚合:聚合出产品数据量的前5名

GET /_search{   "aggs" : {       "products" : {           "terms" : {               "field" : "product",               "size" : 5           }       }   }}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

步骤1: 三个分片的统计计数如下:
这里写图片描述
步骤2:各分片取前5名。
这里写图片描述
步骤3:依据各分片前5名,聚合得出总前5名。
这里写图片描述
仅以产品C的排名作为举例,产品C(50个)的数据来自分片A(6个)和分片C(44个)之和。
所以,排名第三。
实际产品C在分片B中还存在4个,只不过这四个按照排名处于第10位,取前5的时候,显然取不到。
所以,导致聚合结果不准确。
官网有详细举例解读。

2、Elasticsearch要实现聚合后分页,该怎么办?

方案:需要展示满足条件的全部数据条数,即需要全量聚合,且按照某规则排序。
记住,如果数据基数大(十万、百万甚至千万级),这必然会很慢。

步骤1:全量聚合,size设置为: 2147483647。
             ES5.X/6.X版本设置为2147483647 ,它等于2^31-1,
             是32位操作系统中最大的符号型整型常量;ES1.X 2.X版本设置为0。

步骤2:将聚合结果存入内存中,可以考虑list或map存储。
       这里存入list的_id是基于某种规则排序过的,如:基于插入时间。

步骤3:内存内分页,基于list中存储值结合偏移值进行筛选。
       如每页10条数据,取第一页就是:取list中第0到第9个元素,以此类推。

步骤4:基于筛选出的值进行二次查询获取详情。
       此处的筛选条件已经能唯一确定一篇document。

3、“聚合后不能分页,但能分区来取”,是什么鬼?

这里写图片描述
貌似,没有起到分页的作用。此处没有深入研究。

4、聚合后分页实战

步骤1:建立索引

PUT book_index{  "mappings": {  "book_type": {  "properties": {  "_key": {  "type": "keyword",  "ignore_above": 256  },  "pt": {  "type": "date"  },  "url": {  "type": "keyword",  "ignore_above": 256  },  "title": {  "type": "text",  "term_vector": "with_positions_offsets",  "fields": {  "keyword": {  "type": "keyword",  "ignore_above": 256  }  },  "analyzer": "ik_smart"  },  "abstr": {  "type": "text",  "term_vector": "with_positions_offsets",  "fields": {  "keyword": {  "type": "keyword",  "ignore_above": 256  }  },  "analyzer": "ik_smart"  },  "rplyinfo": {  "type": "text",  "term_vector": "with_positions_offsets",  "fields": {  "keyword": {  "type": "keyword",  "ignore_above": 256  }  },  "analyzer": "ik_smart"  },  "author": {  "type": "keyword",  "ignore_above": 256  },  "booktype": {  "type": "keyword",  "ignore_above": 256  },  "price": {  "type": "long"  }  }  }  }}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

步骤2:导入数据

举例原因,假设后来导入百万甚至千万级别数据。

    POST book_index/book_type/1    {     "title":"《Elasticsearch深入理解》",     "author":"ERicif",     "abstr":"Elasticsearch实战书籍",     "relyinfo":"不错,值得推荐",     "booktype":"技术",     "price":79,     "pt":1543611840000    }POST book_index/book_type/2{  "title":"《大数据之路》",  "author":"阿里巴巴",  "abstr":"大数据实现",  "relyinfo":"不错,值得推荐2",  "booktype":"技术",  "price":89,  "pt":1543011840000}POST book_index/book_type/3{  "title":"《人性的弱点》",  "author":"卡耐基",  "abstr":"直击人性",  "relyinfo":"不错,值得推荐2",  "booktype":"励志",  "price":59,  "pt":1543101840000}POST book_index/book_type/4{  "title":"《Flow案例精编》",  "author":"ERicif",  "abstr":"Flow案例",  "relyinfo":"还可以",  "booktype":"技术",  "price":57,  "pt":1543201840000}POST book_index/book_type/5{  "title":"《kibana案例精编》",  "author":"ERicif",  "abstr":"kibana干货",  "relyinfo":"还可以,不孬",  "booktype":"技术",  "price":53,  "pt":1480539840000}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

步骤3:聚合

要求:按照以下条件聚合
1)相同作者出书量;(聚合)
2)相同作者的书,取时间最大的返回。(聚合后排序)

        POST book_index/_search        {          "sort": [          {          "pt": "desc"          }          ],          "aggs": {          "count_over_sim": {          "terms": {          "field": "author",          "size": 2147483647,          "order": {          "pt_order": "desc"          }          },          "aggs": {          "pt_order": {          "max": {          "field": "pt"          }          }          }          }          },          "query": {          "bool": {          "must": [          {          "bool": {          "should": [          {          "match": {          "booktype": "技术"          }          }          ]          }          },          {          "range": {          "pt": {          "gte": 1451595840000,          "lte": 1603201840000          }          }          }          ]          }          },          "_source": {          "includes": [          "title",          "abstr",          "pt",          "booktype",          "author"          ]          },          "from": 0,          "size": 10,          "highlight": {          "pre_tags": [          "<span style=\"color:red\">"          ],          "post_tags": [          "</span>"          ],          "fields": {          "title": {}          }          }        }
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

步骤4:获取关键信息存入list。

步骤5:二次遍历+偏移截取分页实现。

5、Elasticsearch聚合+分页速度慢,该如何优化?

优化方案:改为广度搜索方式。
“collect_mode” : “breadth_first”,
[ES官网]如果数据量越大,那么默认的使用深度优先的聚合模式生成的总分组数就会非常多,但是预估二级的聚合字段分组后的数据量相比总的分组数会小很多所以这种情况下使用广度优先的模式能大大节省内存,从而通过优化聚合模式来大大提高了在某些特定场景下聚合查询的成功率。

6、小结

待聚合的大小size取值越大,结果就越精确,而且计算最终结果的代价也越高;
耗时主要体现在:
第一:分片级别巨大的优先级队列的管理成本;
第二:集群节点和客户端之间的数据传输成本。

7、认知升级

思路优化:
1、聚合后分页的实现通过topHits Agg方式,而非term  Agg。
好处:
1)支持自定义返回字段:_source 方式定义。
2)聚合后返回结果,而非二次再检索。

具体实现:

步骤1:结合原来query实现topHits聚合;并指定待返回字段。

步骤2:考虑分页实现,采取from+size的实现方式。

假定每页限定10条数据,可自定义。
1)取第1-10条,page=1, size=10;top_hits聚合传入的参数是10(10=page*size);

2)取第11—20条,page=2,size=10; top_hits聚合传入的参数是20(20=page*size);
此时,注意:会聚合生成top20的数据,返回给前端的时候,返回最后size条数据;
…..

3)取最后一页,最后几条数据,不一定是10(<=10)条。
举例:假定共187条数据,共应该分成18+1=19页。
最后一页,请求:page=19,size=187-(page-1)*size=7页。
top_hits聚合传入的参数是:190(190=page*size)。

步骤3:组合数据json串,返回给前端。

参考:

[1]Git解读:http://t.cn/RQpTzSH
[2]广度优先遍历:http://t.cn/RHndSgY
[3]分区聚合:http://t.cn/RQpTbdO

——————————————————————————————————
更多ES相关实战干货经验分享,请扫描下方【铭毅天下】微信公众号二维码关注。
(每周至少更新一篇!)

这里写图片描述
和你一起,死磕Elasticsearch
——————————————————————————————————

2018-1-20
作者:铭毅天下 
转载请标明出处,原文地址:
http://blog.csdn.net/laoyang360/article/details/79112946
如果感觉本文对您有帮助,请点击‘顶’支持一下,您的支持是我坚持写作最大的动力,谢谢!

           

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow
这里写图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,目前 Elasticsearch 最新版本是 7.15.1,还没有发布 8.0 版本。不过 Elasticsearch 在 7.x 版本中已经提供了聚合后再分页的支持。 实现聚合后再分页可以参考以下步骤: 1. 创建一个 SearchRequest 对象,设置索引和搜索条件。 2. 使用 AggregationBuilders 构建聚合条件,比如常见的词项聚合、范围聚合、日期直方图聚合等。 3. 将聚合条件添加到 SearchRequest 对象中。 4. 执行搜索,获取 SearchResponse 对象。 5. 从 SearchResponse 中提取聚合结果。 6. 使用 SearchSourceBuilder 构建分页条件,包括起始位置和每页大小。 7. 将分页条件添加到 SearchRequest 对象中。 8. 执行搜索,获取 SearchResponse 对象。 9. 从 SearchResponse 中提取分页结果。 以下是一个简单的示例代码: ```java SearchRequest searchRequest = new SearchRequest("index_name"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 构建聚合条件 AggregationBuilder aggregationBuilder = AggregationBuilders.terms("agg_name").field("field_name"); // 将聚合条件添加到搜索请求中 searchSourceBuilder.aggregation(aggregationBuilder); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); // 获取聚合结果 Terms aggResult = searchResponse.getAggregations().get("agg_name"); // 构建分页条件 searchSourceBuilder.from(0).size(10); // 将分页条件添加到搜索请求中 searchRequest.source(searchSourceBuilder); SearchResponse searchResponse2 = client.search(searchRequest, RequestOptions.DEFAULT); // 获取分页结果 SearchHits hits = searchResponse2.getHits(); ``` 需要注意的是,在 Elasticsearch聚合后再分页需要注意聚合结果的顺序问题,因为分页是在搜索结果返回后进行的,而聚合是在搜索前进行的。如果聚合后进行了排序,则需要在分页时保持相同的排序方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值