Elasticsearch学习(4)—— 聚合查询

为什么80%的码农都做不了架构师?>>>   hot3.png

http://www.cnblogs.com/xing901022/p/4947436.html

ES中的聚合被分为两大类:Metric度量和bucket桶。说的通俗点,metric很像SQL中的avg、max、min等方法,而bucket就有点类似group by

1. Metric聚合

metric的聚合按照值的返回类型可以分为两种:单值聚合 和 多值聚合

1.1 单值聚合

1.1.1 Sum 求和

这个聚合返回的是单个值,dsl可以参考如下:

"aggs" : {

        "intraday_return" : { "sum" : { "field" : "change" } }

  }

intraday_return是聚合的名字,同时也会作为请求返回的id值。另外,聚合中是支持脚本的。

{

    ...

    "aggregations": {

        "intraday_return": {

           "value": 2.18

        }

    }

}

1.1.2 Min 求最小值

{

    "aggs" : {

        "min_price" : { "min" : { "field" : "price" } }

    }

}

1.1.3 Max 求最大值

{

    "aggs" : {

        "max_price" : { "max" : { "field" : "price" } }

    }

}

1.1.4 avg 求平均值

{

    "aggs" : {

        "avg_grade" : { "avg" : { "field" : "grade" } }

    }

}

1.1.5 cardinality 求唯一值,即不重复的字段有多少

{

    "aggs" : {

        "author_count" : {

            "cardinality" : {

                "field" : "author"

            }

        }

    }

}

1.2 多值聚合

1.2.1 percentiles 求百分比

{

    "aggs" : {

        "load_time_outlier" : {

            "percentile_ranks" : {

                "field" : "load_time", 

                "values" : [15, 30]

            }

        }

    }

}

返回结果:

{

    ...

   "aggregations": {

      "load_time_outlier": {

         "values" : {

            "15": 92,

            "30": 100

         }

      }

   }

}

1.2.2 stats 统计

{

    "aggs" : {

        "grades_stats" : { "stats" : { "field" : "grade" } }

    }

}

返回结果:

{

    ...

    "aggregations": {

        "grades_stats": {

            "count": 6,

            "min": 60,

            "max": 98,

            "avg": 78.5,

            "sum": 471

        }

    }

}

1.2.3 extend stats 扩展统计

{

    "aggs" : {

        "grades_stats" : { "extended_stats" : { "field" : "grade" } }

    }

}

返回结果:

{

    ...

    "aggregations": {

        "grade_stats": {

           "count": 9,

           "min": 72,

           "max": 99,

           "avg": 86,

           "sum": 774,

           "sum_of_squares": 67028,

           "variance": 51.55555555555556,

           "std_deviation": 7.180219742846005,

           "std_deviation_bounds": {

            "upper": 100.36043948569201,

            "lower": 71.63956051430799

           }

        }

    }

}

2. Bucket聚合

Bucket可以理解为一个桶,它会遍历文档中的内容,凡是符合要求的就放入按照要求创建的桶中。

它是按照某个字段中的值来分类:比如性别有男、女,就会创建两个桶,分别存放男女的信息。默认会搜集doc_count的信息,即记录有多少男生,有多少女生,然后返回给客户端,这样就完成了一个terms的统计。

 2.1 terms聚合

{

    "aggs" : {

        "genders" : {

            "terms" : { "field" : "gender" }

        }

    }

}

返回结果:

{

    ...

    "aggregations" : {

        "genders" : {

            "doc_count_error_upper_bound": 0, 

            "sum_other_doc_count": 0, 

            "buckets" : [ 

                {

                    "key" : "male",

                    "doc_count" : 10

                },

                {

                    "key" : "female",

                    "doc_count" : 10

                },

            ]

        }

    }

}

2.1.1 terms聚合分析:

2.1.1.1 数据的不确定性

使用terms聚合,结果可能带有一定的偏差与错误性。

举个例子:

我们想要获取name字段中出现频率最高的前5个。

此时,客户端向ES发送聚合请求,主节点接收到请求后,会向每个独立的分片发送该请求。
分片独立的计算自己分片上的前5个name,然后返回。当所有的分片结果都返回后,在主节点进行结果的合并,再求出频率最高的前5个,返回给客户端。

这样就会造成一定的误差,比如最后返回的前5个中,有一个叫A的,有50个文档;B有49。但是由于每个分片独立的保存信息,信息的分布也是不确定的。有可能第一个分片中B的信息有2个,但是没有排到前5,所以没有在最后合并的结果中出现。这就导致B的总数少计算了2,本来可能排到第一位,却排到了A的后面

2.1.1.2 size与shard_size

为了改善上面的问题,就可以使用size和shard_size参数。

  • size参数规定了最后返回的term个数(默认是10个)
  • shard_size参数规定了每个分片上返回的个数
  • 如果shard_size小于size,那么分片也会按照size指定的个数计算

通过这两个参数,如果我们想要返回前5个,size=5;shard_size可以设置大于5,这样每个分片返回的词条信息就会增多,相应的误差几率也会减小

2.1.1.3 order排序

order指定了最后返回结果的排序方式,默认是按照doc_count排序。

{

    "aggs" : {

        "genders" : {

            "terms" : {

                "field" : "gender",

                "order" : { "_count" : "asc" }

            }

        }

    }

}

也可以按照字典方式排序:

{

    "aggs" : {

        "genders" : {

            "terms" : {

                "field" : "gender",

                "order" : { "_term" : "asc" }

            }

        }

    }

}

可以通过order指定一个单值的metric聚合,来排序。

{

    "aggs" : {

        "genders" : {

            "terms" : {

                "field" : "gender",

                "order" : { "avg_height" : "desc" }

            },

            "aggs" : {

                "avg_height" : { "avg" : { "field" : "height" } }

            }

        }

    }

}

多值的Metric聚合,要指定使用的多值字段:

{

    "aggs" : {

        "genders" : {

            "terms" : {

                "field" : "gender",

                "order" : { "height_stats.avg" : "desc" }

            },

            "aggs" : {

                "height_stats" : { "stats" : { "field" : "height" } }

            }

        }

    }

}

2.1.1.4 min_doc_count与shard_min_doc_count

聚合的字段可能存在一些频率很低的词条,如果这些词条数目比例很大,那么就会造成很多不必要的计算。
因此可以通过设置min_doc_count和shard_min_doc_count来规定最小的文档数目,只有满足这个参数要求的个数的词条才会被记录返回。

通过名字就可以看出:

  • min_doc_count:规定了最终结果的筛选
  • shard_min_doc_count:规定了分片中计算返回时的筛选

2.1.1.5 script

桶聚合也支持脚本的使用:

{

    "aggs" : {

        "genders" : {

            "terms" : {

                "script" : "doc['gender'].value"

            }

        }

    }

}

以及外部脚本文件:

{

    "aggs" : {

        "genders" : {

            "terms" : {

                "script" : {

                    "file": "my_script",

                    "params": {

                        "field": "gender"

                    }

                }

            }

        }

    }

}

2.1.1.6 filter

filter字段提供了过滤的功能,使用两种方式:include可以过滤出包含该值的文档;相反则使用exclude。

{

    "aggs" : {

        "tags" : {

            "terms" : {

                "field" : "tags",

                "include" : ".*sport.*",

                "exclude" : "water_.*"

            }

        }

    }

}

2.1.2 多字段聚合

通常情况,terms聚合都是仅针对于一个字段的聚合。因为该聚合是需要把词条放入一个哈希表中,如果多个字段就会造成n^2的内存消耗。

不过,对于多字段,ES也提供了下面两种方式:

    1. 使用脚本合并字段

    2. 使用copy_to方法,合并两个字段,创建出一个新的字段,对新字段执行单个字段的聚合。

例如:实现 select SEX,PROF,COUNT(*) from table group by SEX,PROF

{

    "size": 0,

    "query": {

        "match_all": {}

    },

    "aggs": {

        "sexprof": { //使用脚本合并字段并对新字段执行单字段的聚合

            "terms": {

                "script": {

                    "inline": "doc['SEX.keyword'].value +'-split-'+ doc['PROF.keyword'].value "

                }

            }

        }

    }

}

得到的结果:

{
    "aggregations": {
        "sexprof": {
            "doc_count_error_upper_bound": 5,
            "sum_other_doc_count": 379,
            "buckets": [
                {
                    "key": "女-split-助教",
                    "doc_count": 2
                },
                {
                    "key": "男-split-讲师",
                    "doc_count": 1
                },
                {
                    "key": "男-split-教授",
                    "doc_count": 1
                }
            ]
        }
    }
}

2.1.3 collect模式

对于子聚合的计算,有两种方式:

  • depth_first 直接进行子聚合的计算
  • breadth_first 先计算出当前聚合的结果,针对这个结果在对子聚合进行计算。

默认情况下ES会使用深度优先,不过可以手动设置成广度优先,比如:

{

    "aggs" : {

        "actors" : {

             "terms" : {

                 "field" : "actors",

                 "size" : 10,

                 "collect_mode" : "breadth_first"

             },

            "aggs" : {

                "costars" : {

                     "terms" : {

                         "field" : "actors",

                         "size" : 5

                     }

                 }

            }

         }

    }

}

2.1.4 缺省值Missing value

缺省值指定了缺省的字段的处理方式:

{

    "aggs" : {

        "tags" : {

             "terms" : {

                 "field" : "tags",

                 "missing": "N/A" 

             }

         }

    }

}

2.2 Histogram 直方图聚合

Elasticsearch支持最直方图聚合,它在数字字段自动创建桶,并会扫描全部文档,把文档放入相应的桶中。这个数字字段既可以是文档中的某个字段,也可以通过脚本创建得出的。

2.2.1 桶的筛选规则

2.2.1.1 min_doc_count过滤

返回document数量大于等于1 的直方图聚合

{

    "aggs" : {

        "prices" : {

            "histogram" : {

                "field" : "price",

                "interval" : 50,

                "min_doc_count" : 1

            }

        }

    }

}

2.2.1.2 extend_bounds,指定最小值和最大值边界

默认情况下,ES中的histogram聚合起始都是自动的,比如price字段,如果没有商品的价钱在0-5之间,0这个桶就不会显示。如果最便宜的商品是11,那么第一个桶就是10.

可以通过设置extend_bounds强制规定最小值和最大值,但是要求必须min_doc_count不能大于0,不然即便是规定了边界,也不会返回。

可以通过设置extend_bounds强制规定最小值和最大值,但是要求必须min_doc_count不能大于0,不然即便是规定了边界,也不会返回。

2.2.1.3 order排序

排序大同小异,可以按照_key,_count,指定排序的聚合进行排序

{

    "aggs" : {

        "prices" : {

            "histogram" : {

                "field" : "price",

                "interval" : 50,

                "order" : { "_key" : "desc" }

            }

        }

    }

}

2.2.1.4 keyed设置返回的方式

正常返回的数据如上面所示,是按照数组的方式返回。如果要按照名字返回,可以设置keyed为true。

之前的返回方式:

设置keyed为true:

{

    "aggs" : {

        "prices" : {

            "histogram" : {

                "field" : "price",

                "interval" : 50,

                "keyed" : true

            }

        }

    }

}

 返回的数据为:

{
    "aggregations": {
        "prices": {
            "buckets": {
                "0": {
                    "key": 0,
                    "doc_count": 2
                },
                "50": {
                    "key": 50,
                    "doc_count": 4
                },
                "150": {
                    "key": 150,
                    "doc_count": 3
                }
            }
        }
    }
}

2.2.1.5 缺省的值

缺省值通过MissingValue设置:

{

    "aggs" : {

        "quantity" : {

             "histogram" : {

                 "field" : "quantity",

                 "interval": 10,

                 "missing": 0 

             }

         }

    }

}

 

2.3 Date Histogram聚合 

Date histogram的用法与histogram差不多,只不过区间上支持了日期的表达式。

{

 "aggs":{

    "articles_over_time":{

        "date_histogram":{

            "field":"date",

            "interval":"month"

            }

        }

    }

}

interval字段支持多种关键字:`year`, `quarter`, `month`, `week`, `day`, `hour`, `minute`, `second`

也支持对这些关键字进行扩展使用,比如一个半小时可以定义成如下::

{

    "aggs":{

        "articles_over_time":{

            "date_histogram":{

                "field":"date",

                "interval":"1.5h"

                "format":"yyyy-MM-dd" //对返回结果进行格式化

                }

            }

        }

}

2.3.1 time_zone时区的用法

在es中日期支持时区的表示方法,这样就相当于东八区的时间。

{

    "aggs":{

        "by_day":{

            "date_histogram":{

                "field":"date",

                "interval":"day",

                "time_zone":"+08:00"

            }

        }

    }

}

2.3.2 offset 使用偏移值,改变时间区间

默认情况是从凌晨0点到午夜24:00,如果想改变时间区间,可以通过下面的方式,设置偏移值:

{

"aggs":{

    "by_day":{

        "date_histogram":{

            "field":"date",

            "interval":"day",

            "offset":"+6h"

            }

        }

    }

}

2.3.3 Missing Value缺省字段

当遇到没有值的字段,就会按照缺省字段missing value来计算。

对于其他的一些用法,这里就不过多赘述了,比如脚本、Order、min_doc_count过滤,extended_bounds等都是支持的。

{

  "aggs": {

    "missing_address": {

      "missing": {

        "field": "address"

      }

    }

  }

}

结果只返回一个桶

2.4 嵌套聚合

{

   "aggs":{

      "color_type_max":{

         "terms":{ 

            "field": "color"

         },

         "aggs":{

            "max_age": {

               "max": { 

                 "field" : "age"

               }

             }

         }

      },

      "color_type_min":{

         "terms":{ 

            "field": "color"

         },

         "aggs":{

            "min_age": {

               "min": { 

                 "field" : "age"

               }

             }

         }

      }

   }

}

转载于:https://my.oschina.net/liyurong/blog/1842237

你可能感兴趣的:(Elasticsearch学习(4)—— 聚合查询)