Elasticsearch聚合语句

聚合的范围是search query过滤出的数据

四种聚合类型:

一、Bucketing

桶聚合,常规的分类然后计算每个分类的文档数量

二、Metric

分类并对一组文档进行sum、avg等数学运算

三、Matrix

可在多个字段上计算,生成矩阵结果

四、Pipeline

对聚合的结果再次聚合

Pipeline aggregations 会在所有的聚类执行完毕之后才执行

聚合语句的结构

"aggs" : {
    "<aggregation_name>" : {
        "<aggregation_type>" : {
            <aggregation_body>
        }
        [,"meta" : {  [<meta_data_body>] } ]?
        [,"aggregations" : { [<sub_aggregation>]+ } ]?
    }
    [,"<aggregation_name_2>" : { ... } ]*
}

Terms Aggregation

会根据字段的值动态构建buckets

{
    "aggs" : {
        "genres" : {
            "terms" : { "field" : "genre" }
        }
    }
}

返回:

{
    ...
    "aggregations" : {
        "genres" : {
            "doc_count_error_upper_bound": 0, 
            "sum_other_doc_count": 0, 
            "buckets" : [ 
                {
                    "key" : "jazz",
                    "doc_count" : 10
                },
                {
                    "key" : "rock",
                    "doc_count" : 10
                },
                {
                    "key" : "electronic",
                    "doc_count" : 10
                },
            ]
        }
    }
}

当字段的值很多的时候,elasticsearch只会返回部分buckets,sum_other_doc_count表示没有被返回的 buckets 中 document 的数量之和

size

默认情况下,elasticsearch只会返回按照doc_count降序排序的前10个terms,可以配置size参数来修改这一默认行为

terms聚合的结果是不精确的

https://mp.weixin.qq.com/s/V4cGqvkQ7-DgeSvPSketgQ

比如设置size = 3,表示希望返回TOP3的结果

每个索引分片会取自己分片上TOP3返回协调节点,协调节点汇总后再取汇总结果的TOP3

因此,这个结果是跟全量取TOP3不一样的,所以说terms聚合的结果是不精确的

size 和 shard_size 有什么区别?

  • size:是聚合结果的返回值,客户期望返回聚合排名前三,size值就是 3。
  • shard_size: 每个分片上聚合的数据条数。shard_size 原则上要大于等于 size(若设置小于size,实则没有意义,elasticsearch 会默认置为size)

请求的size值越高,结果将越准确,但计算最终结果的成本也将越高。

推荐设置 shard_size 为比较大的值,官方推荐:size*1.5+10

Order

buckets的排序可以由order参数定义

按doc数量升序排序:

{
    "aggs" : {
        "genres" : {
            "terms" : {
                "field" : "genre",
                "order" : { "_count" : "asc" }
            }
        }
    }
}

按terms的字符升序排序:

{
    "aggs" : {
        "genres" : {
            "terms" : {
                "field" : "genre",
                "order" : { "_term" : "asc" }
            }
        }
    }
}

按子聚类的结果排序:

{
    "aggs" : {
        "genres" : {
            "terms" : {
                "field" : "genre",
                "order" : { "max_play_count" : "desc" }
            },
            "aggs" : {
                "max_play_count" : { "max" : { "field" : "play_count" } }
            }
        }
    }
}

min_doc_count

默认值为1,表示只返回doc_count大于等于1的buckets

{
    "aggs" : {
        "tags" : {
            "terms" : {
                "field" : "tags",
                "min_doc_count": 10
            }
        }
    }
}

Nested Aggregation

针对nested字段的聚合,比如

{
    ...

    "product" : {
        "properties" : {
            "resellers" : { 
                "type" : "nested",
                "properties" : {
                    "name" : { "type" : "text" },
                    "price" : { "type" : "double" }
                }
            }
        }
    }
}

求价格最低的产品的聚合语句可以写成:

{
    "query" : {
        "match" : { "name" : "led tv" }
    },
    "aggs" : {
        "resellers" : {
            "nested" : {
                "path" : "resellers"
            },
            "aggs" : {
                "min_price" : { "min" : { "field" : "resellers.price" } }
            }
        }
    }
}

需要在顶层聚类的path字段填入nested的字段名称,然后,在子聚类中再针对子字段聚类

Date Histogram Aggregation 日期直方图

比如,想要统计每天的商品销量

GET /goods/_search
{
  "query": {
      "bool": {
        "filter": [
          {
            "range": {
              "date_list": {
              "gte": "2020-8-1",
              "lt": "2020-8-2"
              }
            }
          }
        ]
      }
  },
  "size": 0,
  "aggs": {
    "date_count": {
      "date_histogram": {
        "field": "date_list",
        "format": "yyyy-MM-dd",
        "interval": "day"
      }
    }
  }
}

根据过滤的结果数据,以天为间隔聚类绘制直方图

{
  "took": 82,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 34841,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "date_count": {
      "buckets": [
        {
          "key_as_string": "2020-06-02",
          "key": 1591056000000,
          "doc_count": 17
        },
        {
          "key_as_string": "2020-06-03",
          "key": 1591142400000,
          "doc_count": 387
        },
...

会出现6月的聚类结果是因为date_list是一组数据,可能某个document的这个字段即包含8月2日又包含6月2日,那么它将即被放到8-2的桶也被放到6-2的桶

时间间隔

时间间隔单位的可选项:year, quarter, month, week, day, hour, minute, second

精确指定时间间隔:1.5h也可以写成90m

时间格式

在es内部,日期被表示为一个64位的时间戳(milliseconds-since-the-epoch),这正是bucket key字段的值。key_as_string字段的格式可以由format参数决定

如果不指定format,则es会选此字段mapping的第一个日期格式

offset

当使用day作为时间间隔的时候,每个桶的范围是0点至0点,设置offset+6h表示将桶的范围改为6am to 6am

GET my_index/_search?size=0
{
  "aggs": {
    "by_day": {
      "date_histogram": {
        "field":     "date",
        "interval":  "day",
        "offset":    "+6h"
      }
    }
  }
}

Keyed Response

keyed标签置为true表示bucket将以hashmap格式返回,key_as_string作为key

POST /sales/_search?size=0
{
    "aggs" : {
        "sales_over_time" : {
            "date_histogram" : {
                "field" : "date",
                "interval" : "1M",
                "format" : "yyyy-MM-dd",
                "keyed": true
            }
        }
    }
}

Response:

{
    ...
    "aggregations": {
        "sales_over_time": {
            "buckets": {
                "2015-01-01": {
                    "key_as_string": "2015-01-01",
                    "key": 1420070400000,
                    "doc_count": 3
                },
                "2015-02-01": {
                    "key_as_string": "2015-02-01",
                    "key": 1422748800000,
                    "doc_count": 2
                },
                "2015-03-01": {
                    "key_as_string": "2015-03-01",
                    "key": 1425168000000,
                    "doc_count": 2
                }
            }
        }
    }
}

Missing value

如果不定义missingdate字段缺失的文档将被忽略。这样定义后,这些文档会被归入2000/01/01

POST /sales/_search?size=0
{
    "aggs" : {
        "sale_date" : {
             "date_histogram" : {
                 "field" : "date",
                 "interval": "year",
                 "missing": "2000/01/01" 
             }
         }
    }
}

根据聚合的结果进行过滤

https://elasticsearch.cn/article/13501

每个IP登录次数超过5次的IP

{
  "aggs": {
    "IP": {
      "terms": {
        "field": "IP",
        "size": 3000,
        "order": {
          "_count": "desc"
        },
        "min_doc_count": 5
      }
    }
  },
  "size": 0
}

会筛选出大于或等于5的buckets

每个IP登录人数超过2的IP

{
  "aggs": {
    "IP": {
      "terms": {
        "field": "IP",
        "size": 3000,
        "order": {
          "distinct": "desc"
        },
        "min_doc_count": 5
      },
      "aggs": {
        "distinct": {
          "cardinality": {
            "field": "IP.keyword"
          }
        },
        "dd":{
          "bucket_selector": {
            "buckets_path": {"userCount":"distinct"},
            "script": "params.userCount > 2"
          }
        }
      }
    }
  },
  "size": 0
}

bucket_selector必须出现在子聚合中,并且只能针对子聚合的数字结果过滤,script必须返回一个bool

Post Filter

post filter允许用户在执行聚合函数之后再对hits做过滤,比如:

GET /shirts/_search
{
  "query": {
    "bool": {
      "filter": {
        "term": { "brand": "gucci" } 
      }
    }
  },
  "aggs": {
    "colors": {
      "terms": { "field": "color" } 
    },
    "color_red": {
      "filter": {
        "term": { "color": "red" } 
      },
      "aggs": {
        "models": {
          "terms": { "field": "model" } 
        }
      }
    }
  },
  "post_filter": { 
    "term": { "color": "red" }
  }
}

由于aggs的范围取决于query,因此不能在一开始就过滤出颜色为红色的

posted @ 2020-08-17 15:17  luozx207  阅读(1477)  评论(0编辑  收藏  举报