Elasticsearch聚合后分页深入详解

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 1、Elasticsearch支持聚合后分页吗,为什么?不支持,看看Elasticsearch员工如何解读。

image.png

链接

image.pngimage.png这个问题,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: 三个分片的统计计数如下:


image.png

步骤2:各分片取前5名。image.png

步骤3:依据各分片前5名,聚合得出总前5名。image.png

仅以产品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": [

   ""

   ],

   "post_tags": [

   ""

   ],

   "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=pagesize)。


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

参考:

[1]Git解读:http://t.cn/RQpTzSH

[2]广度优先遍历:http://t.cn/RHndSgY

[3]分区聚合:http://t.cn/RQpTbdO

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
2月前
|
存储 搜索推荐 Java
|
7月前
|
缓存 搜索推荐 关系型数据库
Elasticsearch - 闲聊ElasticSearch中的分页
Elasticsearch - 闲聊ElasticSearch中的分页
62 0
|
7月前
|
存储 人工智能 自然语言处理
Elasticsearch Relevance Engine---为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解]
Elasticsearch Relevance Engine---为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解]
Elasticsearch Relevance Engine---为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解]
|
8月前
|
自然语言处理 数据可视化 Java
Spring Data Elasticsearch 聚合查询
如需要统计某件商品的数量,最高价格,最低价格等就用到了聚合查询,就像数据库中的group by
128 0
|
5月前
elasticsearch使用 scroll 滚动分页实战实例
elasticsearch使用 scroll 滚动分页实战实例
142 0
|
1天前
|
存储 缓存 Java
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
Elasticsearch 8.X 聚合查询下的精度问题及其解决方案
8 0
|
3月前
|
存储 SQL Java
聚合在Elasticsearch中的使用及示例验证
聚合在Elasticsearch中的使用及示例验证
72 0
|
3月前
|
测试技术 定位技术 API
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
万字长文:一文彻底搞懂Elasticsearch中Geo数据类型查询、聚合、排序
94622 140
|
3月前
|
iOS开发 索引 MacOS
Elasticsearch 聚合字段aggregate-metric-double
Elasticsearch 聚合字段aggregate-metric-double
25 0
|
3月前
|
缓存 Java API
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)

热门文章

最新文章