Elasticsearch的聚合

一些概念

如同sql里面的group by关键字,Elasticsearch(以下简称es)也是支持聚合、统计的。

es的聚合有两个比较重要的概念:

  • bucket :桶
  • Metrics :指标

Buckets

Buckets简单来说就是满足特定条件的文档的集合。

如同我们经常使用的sql中group by A,B,C…,每个A,B,C等这样的关键字都可以将其视为桶。因为数据库的表都是二维表的形式,es的Buckets并不支持多个字段,但是可以嵌套。这个后续会说到。

Metrics

Metrics 就是对Buckets里面的数据进行各种统计计算。

如同sql里面group by后,你可以使用关键字count、max、avg等来统计,计算最大、最小、平均值。es当然也都支持,而且还有一些更多的sao操作,后续说到。

基本聚合

说明:关于对es的交互,可以先去翻翻我之前写的博文。这里不再累述,仅会给出查询表达式。后续皆是。

aggs关键字

aggs关键字使用规则比较简单:给聚合取个名,指定要聚合的关键字。比如:

{
  "size": 0,
  "aggs": {
    "srvNameAgg": {
      "terms": {
        "field": "srvName"
      }
    }
  }
}

这个就表示对srvName字段进行聚合,“size”:0表示不需要hits的结果。结果如下:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 10000,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "srvNameAgg": {
      "doc_count_error_upper_bound": 81,
      "sum_other_doc_count": 5633,
      "buckets": [
        {
          "key": "sDynSvc",
          "doc_count": 1514
        },
        {
          "key": "sAppQry",
          "doc_count": 518
        },
        ...

聚合的结果是在aggregations.你的聚合名.buckets里面。也可以看到。

嵌套聚合

正如之前所说的。es的聚合并支持多个字段的聚合,也就是说,你不能在一个aggs下多个字段聚合。
BUT,这个问题可以通过别的script方式实现,但是需要改下es原有的配置,有兴趣可以看看这个:https://www.elastic.co/guide/en/elasticsearch/reference/6.3/search-aggregations-metrics-scripted-metric-aggregation.html

其实,我们通过sql group by出来的结果,比如这种,聚合出来的二维表,
https://blog.abreaking.com/upload/2019/09/vftklp9uk0gujqv8f8g7c0qna8.jpg
我们同样可以通过Json节点的形式来进行描述:

{
  "DMDB":{
    "DRS":{
      "DMDB.DRS.DrSendType":"",
      "DMDB.DRS.ProcessExists":"",
    },
    "DRS.B":{
      "DMDB.DRS.B.DrSendType":"",
      "DMDB.DRS.B.ProcessExists":""
    },
    ...
  },
  "HBase":{
    "HMaster":{
      "Hadoop.HBase.HMaster.HaStatus":"",
      "Hadoop.HBase.HMaster.ProcessExists":""
    },
    "HRegionServer":{
      "Hadoop.HBase.HRegionServer.Blocked":"",
      "Hadoop.HBase.HRegionServer.ProcessExists":""
    }
    ...
  },
  "HDFS":{
    "DataNode":{
      "Hadoop.HDFS.DataNode.ProcessExists":""
    },
    "NameNode":{
      "Hadoop.HDFS.NameNode.HaStatus":"",
      "Hadoop.HDFS.NameNode.ProcessExists":""
    }
    ...
  },
  "YARN":{
    ...
  }
}

所以,针对这种多聚合,我们直接嵌套桶(buket)的方式。

{
  "size": 0,
  "aggs": {
    "srvNameAgg": {
      "terms": {
        "field": "srvName"
      },
      "aggs":{
        "retCodeAgg":{
          "terms":{
            "field":"retCode"
          },
          "aggs":{
            "retMsgAgg": {
              "terms": {
                "field": "retMsg"
              }
            }
          }
        }
      }
    }
  }
}

返回结果形如:

{
  ...,
  "aggregations": {
    "srvNameAgg": {
      "doc_count_error_upper_bound": 81,
      "sum_other_doc_count": 5633,
      "buckets": [
        {
          "key": "sPFeeQuery",
          "doc_count": 497,
          "retCodeAgg": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
              {
                "key": "0",
                "doc_count": 465,
                "retMsgAgg": {
                  "doc_count_error_upper_bound": 0,
                  "sum_other_doc_count": 0,
                  "buckets": [
                    {
                      "key": "ok!",
                      "doc_count": 465
                    }
                  ]
                }
              },
              {
                "key": "422001001",
                "doc_count": 32,
                "retMsgAgg": {
                  "doc_count_error_upper_bound": 0,
                  "sum_other_doc_count": 22,
                  "buckets": [
                    {
                      "key": "用户不存在 ERRID:10901775",
                      "doc_count": 1
                    },
                    {
                      "key": "用户不存在 ERRID:13251308",
                      "doc_count": 1
                    }
                  ]
                }
              }
            ]
          }
        },
        {
          "key": "sUserOrdQry",
          "doc_count": 360,
          "retCodeAgg": {
          ...

Tips:重点观察下buckets下面的key及doc_count

需要注意的是,经过本人的测试,聚合嵌套的越多效率也就越地低。尤其是某一层的桶可能返回数据特别多(比如后续说到的对时间粒度的聚合),聚合效率更是尤为低下。

聚合指标

从上面可以看出,es默认是返回了统计的结果,也就是类似数据库的count(*)的结果。它同样也是能支持avg、min、max等计算。

比如:求esb里面服务的平均执行时间:

{
  "size":0,
  "aggs":{
    "srv_aggs":{
      "terms":{
        "field":"srvName"

      },
      "aggs":{
        "avg_executeTime":{
          "avg":{
            "field":"executeTime"
          }
        }
      }
    }
  }
}

结果如下:

"took": 15,
   "timed_out": false,
   "_shards":    {...},
   "hits":    {...},
   "aggregations": {"srv_aggs":    {
      "doc_count_error_upper_bound": 49,
      "sum_other_doc_count": 2607,
      "buckets":       [
                   {
            "key": "sAppQry",
            "doc_count": 2440,
            "avg_executeTime": {"value": 107.825}
         },
                  {
            "key": "sPFeeQuery",
            "doc_count": 1483,
            "avg_executeTime": {"value": 219.701955495617}
         },
                  {
            "key": "sUserOrdQry",
            "doc_count": 1427,
            "avg_executeTime": {"value": 91.43587946741415}
         },
                  {
            "key": "sQryCreditInfo",
            "doc_count": 444,
            "avg_executeTime": {"value": 59.240990990990994}
         },
         ...

The end

聚合是比较费时间的。普通的查询,如term、match,都是通过倒排索引来匹配,其时间复杂度基本上可以视为o(1)。而聚合是会遍历所有的数据,时间复杂度则是o(n),随着多层的嵌套,其时间复杂度线性增长。

所以,最好不要对大量的数据进行聚合,尤其不要嵌套聚合。应该在聚合之前对这大量的数据先过滤,筛选出有意义的数据再进行聚合。

关于过滤+聚合可以参考后续博文。

Reference

官方文档—Aggregations:https://www.elastic.co/guide/en/elasticsearch/guide/current/aggregations.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值