Elasticsearch 聚合学习之四:结果排序
欢迎访问我的 GitHub
这里分类和汇总了欣宸的全部原创(含配套源码): http://github.com/zq2599/blog_demos
本篇概览
-
本文是《Elasticsearch 聚合学习》系列的第四篇,在前面的实战中,聚合的结果以桶(bucket)为单位,放在 JSON 数组中返回,这些数据是没有排序的,今天来学习如何给这些数据进行排序;
系列文章列表
环境信息
-
以下是本次实战的环境信息,请确保您的 Elasticsearch 可以正常运行:
-
操作系统:Ubuntu 18.04.2 LTS
-
JDK:1.8.0_191
-
Elasticsearch:6.7.1
-
Kibana:6.7.1
-
实战用的数据依然是一些汽车销售的记录,在第一章有详细的导入步骤,请参考操作,导入后您的 es 中的数据如下图:
-
接下来一起实战聚合排序吧;
默认排序
-
之前文章中的聚合查询,我们都没有做排序设置,此时 es 会用每个桶的 doc_count 字段做降序,下图是个 terms 桶聚合的示例,可见返回了三个 bucket 对象,是按照 doc_count 字段降序排列的:
内置排序
-
除了自定义排序,es 自身也内置了两种排序参数,可以直接拿来使用:
-
_count:这个参数对应的就是 doc_count,以下请求的排序效果和默认的排序效果是一致的:
GET /cars/transactions/_search
{
"size":0,
"aggs":{
"popular_colors":{
"terms": {
"field": "color",
"order": { ---表示要对聚合结果做排序
"_count": "desc" ---排序字段是doc_count,顺序是降序
}
}
}
}
}
复制代码
-
_key:在区间聚合的时候(histogram 或者 date_histogram),可以根据桶的 key 做排序:
GET /cars/transactions/_search
{
"size": 0,
"aggs": {
"price": {
"histogram": { ---区间聚合
"field": "price", ---取price字段的值
"interval": 20000, ---每个区间的大小是20000
"order": { ---表示要对聚合结果做排序
"_key": "desc" ---排序字段是桶的key值,这里是每个区间的起始值,顺序是降序
}
}
}
}
}
复制代码
-
返回结果如下,已经按照 key 的大小从大到小排序:
......
"aggregations" : {
"price" : {
"buckets" : [
{
"key" : 80000.0,
"doc_count" : 1
},
{
"key" : 60000.0,
"doc_count" : 0
},
{
"key" : 40000.0,
"doc_count" : 0
},
{
"key" : 20000.0,
"doc_count" : 4
},
{
"key" : 0.0,
"doc_count" : 3
}
]
}
}
}
复制代码
-
《Elasticsearch 权威指南》 里指出:**_key**只在 histogram 和 date_histogram 内使用,原文如下图红框所示:
-
但是在实际操作中发现,6.7.1 版本中,除了 histogram 和 date_histogram,terms 桶也可以用**_key**排序,如下图,是按照 key 的字母降序:
-
把 desc 改为 asc 之后返回如下图,变成了按照 key 的首字母升序排序:
-
另外 《Elasticsearch 权威指南》 中还提到一种内置排序类型**_term**,但是 《Elasticsearch官方文档》 中宣布该类型在 6.0 之后已经废弃,如下:
-
也许是"手贱"的缘故,我还是用_term 试了下,可以返回结果,但是会建议用_key 替代_term,如下图:
-
按照 metrics 排序(metrics 结果只有一个值)
-
常见的 metrics 有累加和(sum)、最大值(max)、最小值(min)、平均值(avg),这些 metrics 的特点是处理结果只有一个值,我们可以按照这个结果来排序,例如计算每个汽车品牌的销售额,再按照销售额排序:
GET /cars/transactions/_search
{
"size": 0,
"aggs": {
"sales_rank": {
"terms": { ---桶类型是terms
"field": "make", ---按照make字段聚合
"order": { ---要求排序
"sales": "desc" ---排序字段是sales
}
},
"aggs": {
"sales": { ---metrics处理后的结果保存在名为sales的字段中,排序已经指定了该字段
"sum": { ---桶内的metrics处理,类型是累加
"field": "price" ---将price字段的值累加
}
}
}
}
}
}
复制代码
-
下面是聚合结果,可见已按照每个品牌的销售额大小做了降序的排序:
......
"aggregations" : { ---聚合结果
"sales_rank" : { ---桶名称
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [ ---这个JSON数组内是按照品牌聚合而成的所有桶
{
"key" : "bmw", ---品牌为bmw的桶
"doc_count" : 1, ---文档数量为1
"sales" : { ---metrics处理结果
"value" : 80000.0 ---品牌为bmw的汽车销售总额是80000
}
},
{
"key" : "ford",
"doc_count" : 2,
"sales" : {
"value" : 55000.0
}
},
{
"key" : "honda",
"doc_count" : 3,
"sales" : {
"value" : 50000.0
}
},
{
"key" : "toyota",
"doc_count" : 2,
"sales" : {
"value" : 27000.0
}
}
]
}
}
}
复制代码
按照 metrics 排序(metrics 结果有多个值)
-
和 sum、max 这些只有一个结果的 metrics 不同,extended_stats 的结果包含了数量、最大值、最小值、平均值、累加和等多种处理,此时必须要指定用其中的哪一项(否则会返回错误:Invalid aggregation order path [xxxx]. When ordering on a multi-value metrics aggregation a metric name must be specified):
GET /cars/transactions/_search
{
"size": 0,
"aggs": {
"sales_rank": {
"terms": { ---桶类型是terms
"field": "make", ---按照make字段聚合
"order": { ---要求排序
"stat.avg": "asc" ---排序字段是metrics结果的一个子项(平均值),升序
}
},
"aggs": {
"stat": { ---metrics处理后的结果保存在名为stat的字段中,排序已经指定了该字段的agv子项(平均值)
"extended_stats": { ---桶内的metrics处理,类型是计算数量、最大值、最小值、平均值等多个指标项
"field": "price" ---将price字段的值拿来做metrics处理
}
}
}
}
}
}
复制代码
-
返回结果如下,可见已经按照 metrics 结果的 avg 子项做了升序排序:
......
"aggregations" : {
"sales_rank" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "toyota",
"doc_count" : 2,
"stat" : {
"count" : 2,
"min" : 12000.0,
"max" : 15000.0,
"avg" : 13500.0, ---排序字段
"sum" : 27000.0,
"sum_of_squares" : 3.69E8,
"variance" : 2250000.0,
"std_deviation" : 1500.0,
"std_deviation_bounds" : {
"upper" : 16500.0,
"lower" : 10500.0
}
}
},
{
"key" : "honda",
"doc_count" : 3,
"stat" : {
"count" : 3,
"min" : 10000.0,
"max" : 20000.0,
"avg" : 16666.666666666668, ---排序字段
"sum" : 50000.0,
"sum_of_squares" : 9.0E8,
"variance" : 2.222222222222221E7,
"std_deviation" : 4714.045207910315,
"std_deviation_bounds" : {
"upper" : 26094.757082487296,
"lower" : 7238.5762508460375
}
}
},
......
复制代码
嵌套桶排序
-
在聚合查询中,经常对聚合的数据再次做聚合处理,例如统计每个汽车品牌下的每种颜色汽车的销售额,这时候 DSL 中就有了多层 aggs 对象的嵌套,这就是嵌套桶(此名称来自 《Elasticsearch 权威指南》 ),如下图所示:
-
嵌套桶的排序情况略为复杂,详情请参考 《Elasticsearch聚合的嵌套桶如何排序》 ;
-
至此,聚合返回结果排序的实战已经完成了,后面的章节会深入学习 es 的聚合有关的关键知识点;
欢迎关注 InfoQ:程序员欣宸
- 那些 Go 语言发展历史上的重大决策
- 从趋势到挑战,一站式解读操作系统运维和可观测性
- 百万级 Topic,腾讯云的 Apache Pulsar 稳定性实践
- Apache Doris 在思必驰的应用优化实践:海量语音通话数据下,实时、离线一体的数仓架构设计实践
- 爱数正式开源认知智能开发框架 KWeaver
- 运维智能化的三大关键技术
- “抄我的还‘反捅’我一刀”,Gary Marcus 发文驳斥图灵奖得主 Yann LeCun
- 当出海成为必选项,企业如何构建全场景全生态技术底座?
- 数智底座必备能力三:快速构建创新应用
- Docker 多阶段构建实战 (multi-stage builds)
- 工作笔记之 SELECT 语句在 SAP ABAP 中的用法总结(上)
- 经久不衰的设计定律是不要让我思考的设计
- 不要指望下一个像 GPT 这样的大型语言模型会民主化
- Java 近期新闻:Helidon Níma、Spring Framework、MicroProfile、MicroStream、Kotlin 和 Piranha
- 一文入门 jQuery
- C 学习 ---__libc_open 函数的原理
- 监控系统工作原理
- 甲骨文新微服务框架 Helidon Níma:使用虚拟线程实现高性能
- 【云原生 | 从零开始学 Kubernetes】二、使用 kubeadm 搭建 K8S 集群
- Elasticsearch 聚合学习之四:结果排序