# ElasticSearch 聚合(aggregations) | Syntax | Description | | ----------- | ----------- | | Header | Title | | Paragraph | Text | | Syntax | Description | | ----------- | ----------- | | Header | Title | | Paragraph | Text | ### 特点 + 聚合和搜索是使用同样的数据结构,因此聚合和搜索可以是一起执行的. 这表示我们可以在一次json请求裡,同时对相同的数据进行 搜索/过滤 + 分析 + 桶 和 度量 - 桶(bucket) 1.是按照某种方式对数据进行分组,但不包括计算,因此bucket中往往会嵌套另一种聚合:metrics aggregations即度量 2.桶可以被嵌套在其他桶里面 3.比较常用的桶划分方式有 - Terms Aggregation:根据词条内容分组,词条内容完全匹配的为一组 - filter:一个用来过滤的桶 和用在主查询query的 "过滤filter" 的用法是一模一样的,都是过滤 - top_hits桶 : 在某个桶底下找出这个桶的前几笔hits,返回的hits格式和主查询query返回的hits格式一模一样 - Date Histogram Aggregation:根据日期阶梯分组,例如给定阶梯为周,会自动每周分为一组 - Histogram Aggregation:根据数值阶梯分组,与日期类似 - Range Aggregation:数值和日期的范围分组,指定开始和结束,然后按段分组 - 度量(metrics) 分组完成以后,我们一般会对组中的数据进行聚合运算,例如求平均值、最大、最小、求和等,这些在ES中称为度量 常用的度量集合方式有 - Avg Aggregation:求平均值 - Max Aggregation:求最大值 - Min Aggregation:求最小值 - Percentiles Aggregation:求百分比 - Stats Aggregation:同时返回avg、max、min、sum、count等 - Sum Aggregation:求和 - Top hits Aggregation:求前几 - Value Count Aggregation:求总数 ### aggs 聚合的模板 + 当query和aggs一起存在时,会先执行query的主查询,主查询query执行完后会搜出一批结果,而这些结果才会被拿去aggs拿去做聚合 另外要注意aggs后面会先接一层自定义的这个聚合的名字,然后才是接上要使用的聚合桶 如果有些情况不在意查询结果是什麽,而只在意aggs的结果,可以把size设为0,如此可以让返回的hits结果集是0,加快返回的速度 + 一个aggs裡可以有很多个聚合,每个聚合彼此间都是独立的,因此可以一个聚合拿来统计数量、一个聚合拿来分析数据、一个聚合拿来计算标准差...,让一次搜索就可以把想要做的事情一次做完 + aggs可以嵌套在其他的aggs裡面,而嵌套的桶能作用的文档集范围,是外层的桶所输出的结果集 + 模板 ``` GET /test/doc/_search { "query": { ... }, "size": 0, "aggs": { "custom_name1": { //aggs后面接著的是一个自定义的name "桶": { ... } //再来才是接桶 }, "custom_name2": { //一个aggs裡可以有很多聚合 "桶": { ... } }, "custom_name3": { "桶": { ..... }, "aggs": { //aggs可以嵌套在别的aggs裡面 "in_name": { //记得使用aggs需要先自定义一个name "桶": { ... } //in_name的桶作用的文档是custom_name3的桶的结果 } } } } ``` + 结果模板 ``` { "hits": { "total": 8, "max_score": 0, "hits": [] //因为size设为0,所以没有查询结果返回 }, "aggregations": { "custom_name1": { ... }, "custom_name2": { ... }, "custom_name3": { ... , "in_name": { .... } } } } ``` ### 数据准备 ``` PUT /test { "mappings": { "dynamic": "strict", "properties": { "color": { "type": "keyword" }, "price": { "type": "long" } } } } POST /test/_doc/1 {"color":"red","price":100} POST /test/_doc/2 {"color":"green","price":500} POST /test/_doc/3 {"color":["red","blue"],"price":1000} ``` ### 示例 - trems桶 - 找出共几组颜色和组内颜色个数 ``` GET /test/_search { "size": 0, "aggs": { "my_terms": { "terms": { "field": "color" } } } } ``` 聚合结果 ``` { "aggregations" : { "my_terms" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "red", "doc_count" : 2 }, { "key" : "blue", "doc_count" : 1 }, { "key" : "green", "doc_count" : 1 } ] } } } ``` - 在示例1基础上,对分组的颜色求价格平均和最小值 ``` GET /test/_search { "size": 0, "aggs": { "my_terms": { "terms": { "field": "color" }, "aggs": { "my_avg_price": { "avg": { "field": "price" } }, "my_min_price": { "min": { "field": "price" } } } } } } ``` 聚合结果 ``` { "aggregations" : { "my_terms" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "red", "doc_count" : 2, "my_avg_price" : { "value" : 550.0 }, "my_min_price" : { "value" : 100.0 } }, { "key" : "blue", "doc_count" : 1, "my_avg_price" : { "value" : 1000.0 }, "my_min_price" : { "value" : 1000.0 } }, { "key" : "green", "doc_count" : 1, "my_avg_price" : { "value" : 500.0 }, "my_min_price" : { "value" : 500.0 } } ] } } ``` - filter桶 过滤只查看红颜色的分组情况 ``` GET /test/_search { "size": 0, "aggs": { "my_fliter": { "filter": { "bool": { "must": { "terms": { "color": [ "red" ] } } } } } } } ``` 聚合结果 ``` { "aggregations" : { "my_fliter" : { "doc_count" : 2 } } } ``` filter桶和terms桶叠加嵌套使用 过滤含有红颜色的文档,再对其中包含的颜色进行分组 ``` GET /test/_search { "size": 0, "aggs": { "my_fliter": { "filter": { "bool": { "must": { "terms": { "color": [ "red" ] } } } }, "aggs": { "my_trems": { "terms": { "field": "color" } } } } } } ``` 聚合结果 - 因为terms桶嵌套在filter桶内,所以query查询出来的文档们会先经过filter桶,如果符合filter桶,才会进入到terms桶内 - 此处通过filter桶的文档只有两笔,分别是{"color": "red"}以及{"color": ["red", "blue"]},所以terms桶只会对这两笔文档做分组 - 这也是为什麽terms桶裡没有出现color为green的分组,因为这个文档在filter桶就被挡下来了 - 需注意的是聚合中取的是query之后文档内容,如果query中限制只查询green的文档,那么聚合将无对应内容展示 ``` { "aggregations" : { "my_fliter" : { "doc_count" : 2, "my_trems" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "red", "doc_count" : 2 }, { "key" : "blue", "doc_count" : 1 } ] } } } } ``` 当然也可以先进行trems桶嵌套filter桶,意义则是分组后再进行过滤 ``` GET /test/_search { "size": 0, "aggs": { "my_trems": { "terms": { "field": "color" }, "aggs": { "my_fliter": { "filter": { "bool": { "must": { "terms": { "color": [ "red" ] } } } } } } } } } ``` 聚合结果 - 在分组中进行过滤,可以看到green中my_filter中的doc_count结果为0 - 而至于为什么bule中含有一条doc_count=1,是因为原文档是{"color":["red","blue"]} ``` { "aggregations" : { "my_trems" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "red", "doc_count" : 2, "my_fliter" : { "doc_count" : 2 } }, { "key" : "blue", "doc_count" : 1, "my_fliter" : { "doc_count" : 1 } }, { "key" : "green", "doc_count" : 1, "my_fliter" : { "doc_count" : 0 } } ] } } } ``` - top_hits桶 在某个桶底下找出这个桶的前几笔hits,返回的hits格式和主查询query返回的hits格式一模一样 另外,该桶中不能再嵌套子聚合 Aggregator [my_top_hit] of type [top_hits] cannot accept sub-aggregations - top_hits桶支持的参数 - from、size - sort : 设置返回的hits的排序 要注意,假设在主查询query裡已经对数据设置了排序sort,此sort并不会对aggs裡面的数据造成影响,也就是说主查询query查找出来的数据会先丢进aggs而非先经过sort,因此就算主查询设置了sort,也不会影响aggs数据裡的排序 因此如果在top_hits桶裡的返回的hits数据想要排序,需要自己在top_hits桶裡设置sort 如果没有设置sort,默认使用主查询query所查出来的_score排序 - _source : 设置返回的字段 按价格排序,取前两条记录 ``` GET /test/_search { "size": 0, "aggs": { "my_top_hit": { "top_hits": { "size": 2, "sort": ["price"] #默认升序asc #"sort": {"price":"desc"}这种写法也可以 } } } } ``` 聚合结果 ``` { "aggregations" : { "my_top_hit" : { "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "test", "_type" : "_doc", "_id" : "1", "_score" : null, "_source" : { "color" : "red", "price" : 100 }, "sort" : [ 100 ] }, { "_index" : "test", "_type" : "_doc", "_id" : "2", "_score" : null, "_source" : { "color" : "green", "price" : 500 }, "sort" : [ 500 ] } ] } } } } ```