「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战」
Elasticsearch 除了最基本的搜索,数据分析功能也是十分强大,今天我们就来认识一下 ES 的聚合搜索功能,也可以叫分组搜索,类似于SQL语句中的 group by
。
1. 什么是聚合搜索
聚合可以将你的数据进行汇总,让其称为各种维度的指标,统计数据。聚合可以很好地回答你下面的几个问题:
- 我的网站的平均加载时间是多少?
- 根据交易量,谁是我最有价值的客户?
- 什么会被视为网络上的大文件?
- 每个产品类别中有多少产品?
Elasticsearch 将聚合分为三类:
- 从字段值计算指标(例如总和或平均值)的指标聚合。
- 基于字段值、范围或其他标准将文档分组到桶中的桶聚合,也称为桶。
- 从其他聚合而不是文档或字段获取输入的管道聚合。
下面我们就看一下如何来实现这样聚合。
2. 基本DSL语法
我们首先往 book
索引中插入几条数据,然后就可以来看一下具体效果。
2.1 指标聚合
比如我们想要得到索引里价格的平均值,那么就可以如下这么写:
1 | bash复制代码GET /book/_search |
其中 aggs
是 aggregrations
的缩写,代表是聚合搜索的意思,跟我们之前使用的搜索使用的 query
代表的是常规搜索一样。然后 avg_bucket
是我们自己定义的聚合搜索的名称,其下一层的属性 avg
表示的是要进行的计算,这里的关键字只有 avg
、sum
、max
、min
几种运算,下一层的 field
属性就是要计算的字段,然后我们就可以得到所有图书的平均价格,返回如下结果:
1 | json复制代码{ |
其中 aggregations
就是我们计算得到的结果了,还有如果我们只想返回计算结果,不想返回搜索得到的 hits
值怎么办呢?那么就需要将搜索的 size
设置为0:
1 | bash复制代码GET /book/_search |
就可以得到下面的结果:
1 | json复制代码{ |
2.2 桶聚合
下面呢,我们可以搞一个比较复杂的桶聚合,比如说,我们要看每个图书类目下,价格最贵的一本书是哪本。那么基本逻辑就是,先要按照图书类目进行分组,然后每个类目分组中要有一个价格 top1 的图书。这种就需要使用桶聚合进行搜索了:
1 | json复制代码GET /book/_search |
我们一层一层地看,最外层的 aggs
即为最初的聚合搜索条件,里面的 terms
表示我们需要根据某个字段进行分组,这里设置分组字段为类目ID categoryId
;下面还有一个 aggs
这个聚合搜索为要查询类目下面的内容,属于最外层的 sub_aggregration ,然后我们并不是取的类目下的所有数据,而是只取一条,所以这里是用的 top_hits
的方法,price_top_1
为我们自定义的聚合搜索名称,top_hits
为聚合搜索的关键字,表示这里取部分数据;然后 top_hits
中的属性,就是和我们正常搜索的属性差不多,定义 size: 1
,按照价格 price
倒序排列,表明我们按照价格倒序只取第一条。那么最后得到结果:
1 | ruby复制代码{ |
最后我们得到了分组结果,以及想要的数据。
注:想必聪明的你已经从搜索得到的分组结果里看出来了,分组的排序并不是按照类目ID进行排序的。这里分组的默认排序条件有两个:一个是 doc_count
,即分组中的文档数量,默认是降序排列,文档数越多越靠前;另一个是 _key
,即分组的key值,默认是生序排序,基本就是数字排序或者字符排序了。那么该怎么定义聚合搜索排序呢?这个大家可以自行探索一下。
3. Java代码
那么问题来了,我们怎么通过 Java 代码来实现 2.2 中的 DSL 语句呢?
套路还是固定的,首先需要构建一个搜索请求,然后组装搜索条件,只不过由原先的查询条件,变成了现在的聚合条件,代码如下:
1 | java复制代码 private SearchResponse searchGroupData() { |
上面就是我们的查询代码,然后就算得到了结果,怎么解析得到我们想要的结果呢?我简单写了一个示例,大家可以自行参考:
1 | ini复制代码 @Override |
总结
本文我们简单展示了一下聚合搜索可以做的事情,但是不只是这些,还有一些未展示的内容,需要大家自己去尝试,比如聚合后结果如何进行分页,如何统计分组总数,排序是怎么自定义的等等。如果你遇到了问题,或者有了自己的方法,我们也可以一起交流一下,共同探讨。
链接
本文转载自: 掘金