大数据搜索与挖掘及可视化管理方案 :Elastic Stack 5:Elasticsearch、Logstash、Kibana、X-Pack、Beats (第3版)
上QQ阅读APP看书,第一时间看更新

3.4 聚合

聚合(aggregations)可以看作是对查询结果的汇总,比如先查询出某个时间段的HTTP请求,然后统计每天的数据。aggregations真正强大的功能在于它能嵌套并实现多级汇总,每一种aggregation都有自己的目的和输出,它们通常分为四类:metric、bucket、pipeline和matrix。这一节主要对aggregations进行介绍,涉及bucket aggregations、metric aggregations、pipeline aggregations、matrix aggregations等。

在aggregations中会用到“bucket”的概念。所谓的“bucket”,是满足某个条件的文档集合,它和关系型数据库中的SQL语句中的“groupby”子句的作用相似(但又不一样)。例如,在校大学生要么属于本科生群的bucket,要么属于研究生群的bucket。

metric是为某个bucket中的文档计算得到的统计信息,它和关系型数据库中的SQL语句中的集函数如count()、max()等的作用相似。可见,aggregations聚合是由一个或多个buckets、零个或者多个metrics组合而成的统计结果。每个文档中的值会被计算来决定它们是否匹配了某些bucket的条件,如果匹配成功,那么该文档会被置入该bucket中。一个bucket也能够嵌套在其他的bucket中(即bucket是可以嵌套的)。对metrics而言,多数仅使用文档中的值进行简单计算。另外,aggregations也支持排序等属性,本书将会在相关例子中进行说明。

Matrix是一种在多字段上操作、从请求的文档字段中提取信息、返回矩阵结果的聚合方式。与bucket和metric不同的是,这一方式尚不支持script语句。

pipeline是将其他aggregations的输出及其关联度量进行聚合的方式。

3.4.1 metrics aggregations

metrics aggregations基于从文档中提取的值来计算指标。这些值通常使用字段数据,也可以使用脚本生成。这一节将对metrics aggregations中的min、max、sum、avg、stats、extended_stats、value_count等聚合进行介绍。

1.min、max、sum、avg聚合

在aggregations中可以方便地完成对最值、求和、均值等的统计。代码段3.33完成对指定字段的最小值聚合,示例结果如图3.8所示(当统计最大值时,将代码段3.33中的统计函数换成max即可,这里不再赘述)。

    //代码段3.33:执行最小值聚合    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "min_size": {               //aggs的名称
          "min": {                  //统计最小值。当统计最大值时这里换成max即可。
            "field": "log_size"     //统计字段
          }
        }
      }
    }'

图3.8 最小值聚合结果

类似地,求和、求平均统计只需在相应函数处写上sum及avg即可。代码段3.34完成对指定字段的平均值聚合,而针对返回HTTP响应大小size字段的实际效果如图3.9所示。

    //代码段3.34:执行平均值聚合   
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "avg_size": {                //aggs的名称
          "avg": {                   //统计平均值。当求和时这里换成sum即可。
            "field": "log_size"
          }
        }
      }
    }'

图3.9 平均值聚合结果

在完成上述计算时,同样支持script脚本的使用。代码段3.35中使用了script,用来计算log_size的最大值,示例如图3.10所示。

    //代码段3.35:执行平均值聚合    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "max_with_script": {
          "max": {
            "script": {
              "inline": "doc['log_size'].value",       //在脚本中指定log_size
              "lang": "painless"
            }
          }
        }
      }
    }'

图3.10 使用script执行最大值聚合

2.stats、extended_stats聚合

stats aggregation是一个多值统计,返回值包括计数、最小值、最大值、平均值、求和等。代码段3.36演示了对相应字段进行多值统计的方法,针对类型文件log的返回结果如图3.11所示。同样,stats aggregation也支持使用脚本script和参数,不再赘述。

    //代码段3.36:执行 stats聚合    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "log_size_stats": {
          "stats": {
            "field": "log_size"
          }
        }
      }
    }'

图3.11 stats聚合多值统计结果

extended_stats aggregation则是对一般的stats aggregation的功能扩展,可以在上述输出结果上添加平方和、方差和标准差等指标,参见代码段3.37,运行结果如图3.12所示。同样地,extended_stats aggregation也支持script和参数,不再赘述。

    //代码段3.37:执行 extended_stats聚合    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "log_size_extended_stats": {
          "extended_stats": {
            "field": "log_size"
          }
        }
      }
    }'

图3.12 extended_stats聚合结果

3.value_count聚合

value_count aggregation是一种单值指标聚合,用来计算文档中某个字段的统计数量。首先执行代码段3.38,为text类型的custom_ip字段开启fielddata功能,然后执行代码段3.39对该字段执行value_count聚合,统计某服务器日志记载的访问次数,结果如图3.13所示。

    //代码段3.38:为字段 custom_ip开启 fielddata功能    
    curl-XPUT localhost:9200/whale/_mapping/log-d'{
                                                //这里使用PUT方法,索引/_mapping/类型
      "properties": {
        "custom_ip": {                          //要开启fielddata功能的字段
          "type": "keyword",                    //字段的类型,应与实际类型一致
          "fielddata": true
        }
      }
    }'

//代码段3.39:执行 value_count聚合,统计访问次数

    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "custom_ip_count": {
          "value_count": {
            "field": "custom_ip"
          }
        }
      }
    }'

图3.13 访问次数统计结果

3.4.2 bucket aggregations

1.terms聚合

terms aggregation用于对指定字段的内容进行分布统计。聚合过程中会动态构建多个bucket,并对每个bucket计算出一个特定的值。代码段3.40实现了对某服务器上的不同访问用户使用的不同操作系统的统计,结果如图3.14所示。需要注意,代码中的os字段也需要开启fielddata,方法参照代码段3.38。

    //代码段3.40:执行 terms聚合,统计访问者操作系统类型    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "usage": {
          "terms": {
            "field": "os"
          }
        }
      }
    }'

图3.14 对访问用户的操作系统的统计结果

2.range聚合

range aggregation基于多个bucket,每个bucket中定义一组范围,用于统计字段在某个范围的值。在聚合过程中,从每个文档提取的值将针对每个范围进行检查,并且返回“相关”或“匹配”的文档。代码段3.41实现了对log_size字段分别在三种范围内的数量统计,结果如图3.15所示。

    //代码段3.41:执行三种不同范围的 range聚合   
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "log_size_ranges": {
          "range": {
            "field": "log_size",
            "ranges": [
              {"to":300},
              {"from":222, "to":500},
              {"from":222}
            ]
          }
        }
      }
    }'

图3.15 range聚合统计结果

可以使用keyed参数并将这个参数置为true,这样可以将返回值中的key作为这个JSON对象的名称。也可以使用key参数来自定义key的名称,如代码段3.42所示,它演示了针对类型文件log,分析字段log_size在三个不同区段内的统计值,结果如图3.16所示。同样,range aggregation也支持script和script参数,不再赘述。

    //代码段3.42:使用 keyed参数,执行三种不同范围的 range聚合   
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "log_size_ranges": {
          "range": {
            "field": "log_size",
            "keyed": true,
            "ranges": [
              {"key": "short", "to":222},
              {"key": "middle",
                      "from":222, to":300},
              {"key": "long", "from":300}
            ]
          }
        }
      }
    }'

图3.16 带有keyed参数的range聚合统计结果

3.histogram聚合

histogram aggregation是一种可以根据其返回值(针对数值型或日期型的字段)生成将来可生成柱状图的聚合数据。代码段3.43是计算log_size字段每间隔1000的统计分布情况,针对类型文件log的返回结果如图3.17所示。通过上面的聚合分析,可以得到log_size在各个区段的数量。在这个基础上,可以利用一些可视化软件对上述数据生成一张图表。

    //代码段3.43:执行柱状图聚合,统计 log_size字段在固定间隔不同区段中的数量    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "log_size_histogram": {
          "histogram": {
            "field": "log_size",
            "interval":1000,         //固定区间 1000
            "order": {
              "_key": "desc"         //降序排序
            }
          }
        }
      }
    }'

图3.17 为柱状图执行聚合统计数据

也可以在histogram aggregations中添加子聚合来实现在现有的聚合中再次嵌套进行统计。代码段3.44实现了对每一个聚合中再次进行stats aggregation并按照子聚合中的最小值字段(即代码中的size_stats.min)进行降序排序的实现方法,针对类型文件log的实际运行效果如图3.18所示。

    //代码段3.44:执行柱状图聚合,统计 log_size字段在固定间隔不同区段中的数量    
    curl-XPOST localhost:9200/whale/log/_search-d'{
    "aggs": {
        "outer_bucket": {
          "histogram": {
            "field": "log_size",
            "interval":500,
            "order": {"size_stats.min": "asc"}
          },
          "aggs": {
            "size_stats": {
              "stats": {"field": "log_size"}
            }
          }
        }
      }
    }'

在上述例子中可以为中间结果取名,只需使用keyed参数并将其设置为true,即代码段3.44的field和interval语句中间加入语句"keyed":true并在末尾加逗号。这样,前端程序可以通过这个名字来取得相应的统计结果并进行展示,该聚合的查询结果如图3.19所示。请注意图3.18和图3.19的区别:图3.18的buckets结果是以数组方式给出的,而图3.19的buckets则是以键值对的形式给出的。

图3.18 执行嵌套的聚合

图3.19 对中间结果取名的histogramaggregations

4.date_histogram聚合

date_histogram aggregation是一个增强型的专门针对于日期型字段统计的histogram aggregation,它允许使用year、month、week、day、hour、minute等常量作为interval属性的取值。在代码段3.45中,实现了在field中填写一个日期类型的字段名称、在interval中写一个步长值、通过format参数设置时间格式的方法,结果如图3.20所示。

    //代码段3.45:执行时间柱状图聚合,统计日志记录在不同时间段中的数量    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "logs_over_time": {
          "date_histogram": {
            "field": "timestamp",
            "interval": "3h",             //步长为三小时
            "format":"dd/MM/yyyy HH:mm:ss"    //根据Elasticsearch中实际数据设置时间格式
          }
        }
      }
    }'

图3.20 各个时间段的时间柱状图聚合结果

也可以在其中添加子aggregations(即嵌套)来实现更丰富的统计。代码段3.46实现了以3小时为步长单位,统计每小时各个状态码的出现次数。实际运行效果如图3.21所示。

    //代码段3.46:执行嵌套的聚合,统计状态码在不同时间段中的数量    
    curl-XPOST localhost:9200/whale/log/_search-d'{
    "aggs": {
        "logs_over_time": {
          "date_histogram": {
            "field": "timestamp",
            "interval": "3h",                //步长为 3小时
            "format": "dd/MM/yyyy HH:mm:ss"   //根据Elasticsearch中实际数据设置时间格式
          },
          "aggs": {
            "status_code": {
              "terms": {
                "field": "status_code",
                "order": {"_term": "asc"}
              }
            }
          }
        }
      }
    }'

图3.21 状态码出现次数的部分统计结果

5.date_range聚合

date_range aggregations是专门对于时间类型的字段进行区段统计的聚合。下面的代码段3.47介绍了其基本使用方法,在特定时间区段中日志数量的统计结果如图3.22所示。

    //代码段3.47:执行特定时间范围内的聚合统计    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "range": {
          "date_range": {
            "field": "timestamp",
            "format": "dd/MM/yyyy HH:mm:ss", //根据Elasticsearch中实际数据设置时间格式
            "ranges": [
              {"to": "14/12/2016 14:00:00"},       //截止时间
              {"from": "14/12/2016 07:00:00"}      //起始时间
            ]
          }
        }
      }
    }'

图3.22 指定时间段内的日志数量统计结果

6.filter聚合

类似于SQL语句中where子句的作用,filter aggregation可以为当前文档集合定义一个过滤条件来缩小现有的数据集,凡满足定义的过滤条件(filter)的文档(document)都会被放入这个bucket中。代码段3.48展示了对类型文件log中所有size字段大于300的文档进行平均值统计(均值统计是在嵌套的aggregations中实现的),相当于满足指定条件后再进行的统计。针对类型文件log的实际效果如图3.23所示。

    //代码段3.48:执行带有过滤的聚合统计    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "filter_aggregation": {
          "filter": {
            "range": {
              "log_size": {"gt":300}        //规定日志信息长度大于 300
            }
          },
          "aggs": {
            "avg_log_size": {
              "avg": {"field": "log_size"}  //聚合中求平均值
            }
          }
        }
      }
    }'

图3.23 带有过滤的聚合统计结果

3.4.3 pipeline aggregations

pipeline aggregations处理的对象是其他聚合的输出(而不是文档),这种聚合方式可向输出树添加信息。pipeline aggregations包含很多形式,能够处理不同的任务,大致分为两类:

(1)parent:接收其父聚合的输出,并计算出新的buckets或新的聚合来添加到现有的buckets中。

(2)sibling:接收同级聚合的输出,并计算出新的同级聚合。

pipeline aggregations一般无子聚合,但是它可以在buckets_path中引用另一个管道,这样pipeline aggregations就可以被链接在一起。例如,可以将两个计算导数的pipeline aggregations链接在一起以计算二阶导数。这一节将对pipeline aggregations中的min_bucket、max_bucket、sum_bucket、avg_bucket、stats_bucket、extended_stats_bucket等聚合进行介绍。

1.min_bucket、max_bucket、sum_bucket、avg_bucket聚合

min_bucket和max_bucket聚合是上文提到的聚合的同级聚合,这样的聚合以同级聚合中特定指标的最小值来识别buckets,并且输出bucket的值及其key。这里的指标必须为数字类型,同级聚合必须是支持多个buckets的聚合。代码段3.49实现了对每小时出现日志记录长度最小值的计算,结果如图3.24所示。

    //代码段3.49:计算每小时出现的日志记录长度最小值    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "access_per_hour": {         //外围聚合,统计每小时访问量
          "date_histogram": {
            "field": "timestamp",
            "interval": "hour"
          },
          "aggs": {                  //子聚合,统计log_size总数
            "access": {
              "sum": {"field": "log_size"}
            }
          }
        },
        "min_access_per_hour": {     //管道聚合,链接上面两种聚合
          "min_bucket": {
            "buckets_path": "access_per_hour>access"
          }
        }
      }
    }'

计算每小时出现日志记录长度最大值时,只需将代码段3.49中的min_bucket改为max_bucket即可(可以与聚合的名字一并修改),得到的结果如图3.25所示。另外sum_bucket和avg_bucket聚合也是这样的修改和执行方法,这里不再一一赘述。

图3.24 每小时日志记录长度最小值统计结果

图3.25 每小时日志记录长度最大值统计结果

2.stats_bucket、extended_stats_bucket聚合

与上面提到的四种管道聚合类似,stats_bucket聚合能够返回包含计数、最小值、最大值、平均值、求和的多值统计结果。代码段3.50实现了每小时日志记录长度的多值统计,结果如图3.26所示。

    //代码段3.50:计算每小时出现的日志记录长度计数、最小值、最大值、平均值、求和    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "access_per_hour": {           //外围聚合,统计每小时访问量
          "date_histogram": {
            "field": "timestamp",
            "interval": "hour"
          },
          "aggs": {               //子聚合,统计log_size总数
            "access": {
              "sum": {"field": "log_size"}
            }
          }
        },
        "min_access_per_hour": {  //管道聚合,链接上面两种聚合
          "min_bucket": {
            "buckets_path": "access_per_hour>access"
          }
        }
      }
    }'

图3.26 每小时日志记录长度的多值统计结果

extended_stats_bucket聚合能够在stats_bucket聚合计算出的结果上添加平方和、方差和标准差等指标,只需将代码段3.50中的stats_bucket改为extended_stats_bucket即可(可以与聚合的名字一并修改),得到的结果如图3.27所示。

图3.27 基于extended_stats_bucket aggregation的每小时日志记录长度的多值统计结果

3.4.4 matrix aggregations

matrix aggregations根据从所请求的文档字段提取的值,对多个字段进行操作,并返回矩阵结果。这一聚合方式与前面提到的metric aggregations、bucket aggregations等均不同,它不支持script操作。这一节将对matrix aggregations中的matrix_stats聚合进行介绍。

matrix_stats聚合是一种面向数值的聚合,用于计算一组文档字段中的以下统计信息:

· 计数:计算过程中每种字段的样本数量;

· 平均值:每个字段数据的平均值;

· 方差:每个字段样本数据偏离平均值的程度;

· 偏度:量化每个字段样本数据在平均值附近的非对称分布情况;

· 峰度:量化每个字段样本数据分布的形状;

· 协方差:一种量化描述一个字段数据随另一个字段数据变化程度的矩阵;

· 相关性:描述两个字段数据之间的分布关系,其协方差矩阵取值在[-1,1]之间。

它主要用于计算两个数值型字段之间的关系,代码段3.51实现了对日志记录长度和HTTP状态码之间关系的计算,结果如图3.28所示。

    //代码段3.51:计算日志记录长度和 HTTP状态码之间的关系    
    curl-XPOST localhost:9200/whale/log/_search-d'{
      "aggs": {
        "matrixstats": {
          "matrix_stats": {
            "fields": [
              "log_size",
              "status_code"
            ]
          }
        }
      }
    }'

图3.28 使用matrix_stats aggregation计算log_size和status_code之间的关系