7

es笔记六之聚合操作之指标聚合 - XHunter

 1 year ago
source link: https://www.cnblogs.com/hunterxiong/p/17429764.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文首发于公众号:Hunter后端
原文链接:es笔记六之聚合操作之指标聚合

聚合操作,在 es 中的聚合可以分为大概四种聚合:

  • bucketing(桶聚合)
  • mertic(指标聚合)
  • matrix(矩阵聚合)
  • pipeline(管道聚合)

bucket
类似于分类分组,按照某个 key 将符合条件的数据都放到该类别的组中

mertic
计算一组文档的相关值,比如最大,最小值

matrix
根据多个 key 从文档中提取值生成矩阵,这个操作不支持脚本(script)

pipeline
将其他聚合的结果再次聚合输出

聚合是支持套娃(嵌套)操作的,你可以在聚合的结果上接着进行聚合操作,es 是不限制聚合的深度的。

本篇笔记目录如下:

  1. 指标聚合的基本结构
  2. 平均值聚合
  3. 聚合统计汇总
  4. 最大值、最小值聚合
  5. 百分位统计
  6. 百分位排名
  7. 字符串统计聚合
  8. sum 统计总和操作
  9. count 统计总数操作
  10. top hit 操作

1、指标聚合的基本结构

指标聚合操作的基本结构大致如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "aggregation_name": {
      "agg_name": {
        "field": "field_name"
      }
    }
  }
}

其中,aggregation_name 为聚合返回结果的名称,由我们自己定义,agg_name 为聚合的参数,比如最大值最小值,平均值等,这个我们在下面介绍。

指标聚合

指标聚合是从文档中提取字段值出来进行计算得出结果,比如最大最小平均值等。

接下来将详细介绍各种指标聚合操作。

2、平均值聚合

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "avg_balance": {
      "avg": {
        "field": "balance"
      }
    }
  }
}

其中,最外层的 aggs 表示是聚合操作,avg_balance 是聚合的名称,avg 则表示是平均值聚合,里面的 field 表示聚合的字段是 balance 字段

在这里,如果不添加 size=0,除了会返回我们的聚合结果,还会返回聚合的源数据。

这个操作我们返回的结果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1000,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg_balance" : {
      "value" : 25714.837
    }
  }
}

我们聚合的结果在 aggregations 这个 key 下。

脚本执行

脚本执行的方式如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "avg_balance": {
      "avg": {
        "script": {"source": "doc.balance.value"}
      }
    }
  }
}

对结果处理

假设,我们需要对这个平均值结果进行处理,比如我们计算出来的这个值是 2000,我们想要对这个值进行修正,比如乘以 1.2。

当然,这个乘的操作我们可以获取数据之后在系统里进行操作,如果是直接在 es 的处理中,我们可以如下实现:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "avg_corrected_balance": {
      "avg": {
        "field": "balance", 
        "script": {
          "lang": "painless",
          "source": "_value * params.correction",
          "params": {"correction": 1.2}
          
        }
      }
    },
    "avg_balance": {
      "avg": {
        "script": {"source": "doc.balance.value"}
      }
    }
  }
}

在上面的语句中,我们新增了一个 params 字段,定义了一个 correction 的值,然后返回的结果乘以了这个值。

在这里,我额外加了一个 avg_balance,是直接用的平均值聚合结果,主要是用来对比这两个结果。

缺失值补充

有一些情况,我们在导入数据的时候,可能某条数据的某个字段是没有值的,默认情况下他们是会被忽略的,不计入计算的,但是如果想要为其加一个默认值也是可以实现的,这里我们用到 missing 这个参数来定义:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "avg_balance": {
      "avg": {
        "field": "balance",
        "missing": 0
      }
    }
  }
}

3、去重统计

是对某个字段进行去重后统计总数,操作如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_count": {
      "cardinality": {
        "field": "age"
      }
    }
  }
}

需要注意的是,这个统计对于 text 字段属性是不生效的

4、聚合统计汇总

有一个聚合统计汇总的参数 stats,可以将一般的聚合值进行汇总后返回,比如总数,最大值,最小值等,使用如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_stats": {
      "stats": {
        "field": "age"
      }
    }
  }
}

可以看到返回的值如下:

{
 ...
 "aggregations" : {
    "age_stats" : {
      "count" : 1000,
      "min" : 20.0,
      "max" : 40.0,
      "avg" : 30.171,
      "sum" : 30171.0
    }
  }
}

如果还想获得方差,标准差等数据,可以使用这个参数的扩展版 extended_stats,替换聚合的参数 stats 即可。

5、最大值、最小值聚合

最大值最小值的关键字是 max 和 min,使用示例如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "max_age": {
      "max": {"field": "age"}
    },
    "min_age": {
      "min": {"field": "age"}
    }
  }
}

使用脚本的方式来实现:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "max_age": {
      "max": {"script": {"source": "doc.age.value"}}
    }
  }
}

6、百分位统计

使用 es 进行百分位的统计,用到的关键字是 percentiles

使用示例如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_percentiles": {
      "percentiles": {
        "field": "age"
      }
    }
  }
}

会输出 [1, 5, 25, 75, 95, 99] 的统计数:

{
  ...
  "aggregations" : {
    "age_percentiles" : {
      "values" : {
        "1.0" : 20.0,
        "5.0" : 21.0,
        "25.0" : 25.0,
        "50.0" : 30.8,
        "75.0" : 35.0,
        "95.0" : 39.0,
        "99.0" : 40.0
      }
    }
  }
}

我们也可以指定统计的百分位的数列表,比如我们只想知道 [75, 98, 99, 99.9] 的数据:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_percentiles": {
      "percentiles": {
        "field": "age",
        "percents": [75, 98, 99, 99.9]
      }
    }
  }
}

我们直接使用是返回的百分位-数据的格式,我们也可以使用 {'key': xx, 'value': xx} 来返回一个列表,加上一个参数 keyed=false 即可

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_percentiles": {
      "percentiles": {
        "field": "age",
        "keyed": false
      }
    }
  }
}

返回的结果示例如下:

    "age_percentiles" : {
      "values" : [
         ...
        {
          "key" : 75.0,
          "value" : 35.0
        },
        {
          "key" : 95.0,
          "value" : 39.0
        },
        {
          "key" : 99.0,
          "value" : 40.0
        }
      ]
    }
  }
}

7、百分位排名

这个是和前面的百分位统计相反的操作。

前面是根据百分位获取该百分位值,这个参数的作用是根据数据获取在系统中的百分位,使用示例如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_ranks": {
      "percentile_ranks": {
        "field": "age",
        "values": [
          30,
          35,
          40
        ]
      }
    }
  }
}

8、字符串统计聚合

对于字符串类型的数据,有一个专门的参数来获取相应的聚合统计值,为 string_stats

对 lastname 字段的统计示例如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "last_name_stats": {
      "string_stats": {"field": "lastname.keyword"}
    }
  }
}

需要注意,如果我们需要进行统计的字段如果是 text 字段,那么就需要加上 .keyword 来进行统计,如果是字段属性是 keyword,就不需要这样处理。

经过统计返回的数据如下:

  ... 
  "aggregations" : {
    "last_name_stats" : {
      "count" : 1000,
      "min_length" : 2,
      "max_length" : 11,
      "avg_length" : 6.122,
      "entropy" : 4.726472133462717
    }
  }
}

以上信息包括数据总数,lastname 字段最长和最短长度,平均长度和熵值

9、sum 统计总和操作

比如我们需要对 bank 这个数据库的 age 字段进行 sum 的操作,可以如下操作:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_sum": {
      "sum": {"field": "age"}
    }
  }
}

在前面的每一个聚合操作里,都可以进行 query 的条件筛选,比如获取 age=21 的数据的 sum 值:

GET /bank/_search
{
  "size": 0,
  "query": {"match": {"age": "21"}}, 
  "aggs": {
    "age_sum": {
      "sum": {"field": "age"}
    }
  }
}

10、count 统计总数操作

count 是统计总数,使用示例如下:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "age_count": {
      "value_count": {
        "field": "age"
      }
    }
  }
}

11、top hit 操作

top hit 操作是根据条件返回符合条件的前几条数据,通过 size 控制返回的数量。

我们先来看下下面的这个操作:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "top_ages": {
      "terms": {
        "field": "age",
        "size": 30
      }
    }
  }
}

这个操作其实就是一个桶聚合,它会在下一篇笔记中介绍,这里我们直接用一下,它返回字段为 age,以及它在文档中的数量:

  ...
  "aggregations" : {
    "top_ages" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 31,
          "doc_count" : 61
        },
        {
          "key" : 39,
          "doc_count" : 60
        },
        {
          "key" : 26,
          "doc_count" : 59
        },
        ...

top_hits 的操作是在第一个 aggs 聚合操作条件下,进行再次聚合。

比如我们想要获取各个 age 的数据中,按照 balance 字段进行倒序排序的前三个,我们可以如下操作:

GET /bank/_search
{
  "size": 0,
  "aggs": {
    "top_ages": {
      "terms": {
        "field": "age",
        "size": 30
      },
      "aggs": {
        "top_balance_hits": {
          "top_hits": {
            "size": 3,
            "sort": [{"balance": {"order": "desc"}}]
          }
        }
      }
    }
  }
}

然后在第一次聚合返回的结果中,就会多一个 top_balance_hits 字段,也就是我们在查询操作中指定的,其下会有三条按照 balance 字段倒序返回的数据:

  ...
  "aggregations" : {
    "top_ages" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 31,
          "doc_count" : 61,
          "top_balance_hits" : {
            "hits" : {
              "total" : {
                "value" : 61,
                "relation" : "eq"
              },
              "max_score" : null,
              "hits" : [
                ...
              ]
        },
        {
          "key" : 39,
          "doc_count" : 60,
          ...
        },
        {
          "key" : 26,
          "doc_count" : 59,
          ...
        },
        ...

如果想获取更多后端相关文章,可扫码关注阅读:

image

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK