Skip to main content

移动函数聚合 moving_fn

Moving Function Aggregation

给定一系列有序的数据,移动函数聚合将在数据上滑动一个窗口,并允许用户指定在每个数据窗口上执行的自定义脚本。为方便起见,预定义了许多常用函数,如min/max, moving averages ...

语法

{
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.min(values)"
}
}

moving_fn聚合必须嵌入到直方图或日期直方图聚合中。它们可以像任何其他度量聚合一样嵌入:

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_movfn": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.unweightedAvg(values)"
}
}
}
}
}
}

移动平均值是通过首先在字段上指定直方图或date_histogram来构建的。然后,您可以选择在直方图内添加数字度量,例如moving_fn被嵌入到直方图中。然后使用buckets_path参数“指向”直方图内的一个同级metric。

上述聚合的示例响应如下:

{
"took": 11,
"timed_out": false,
"_shards": ...,
"hits": ...,
"aggregations": {
"my_date_histo": {
"buckets": [
{
"key_as_string": "2015/01/01 00:00:00",
"key": 1420070400000,
"doc_count": 3,
"the_sum": {
"value": 550.0
},
"the_movfn": {
"value": null
}
},
{
"key_as_string": "2015/02/01 00:00:00",
"key": 1422748800000,
"doc_count": 2,
"the_sum": {
"value": 60.0
},
"the_movfn": {
"value": 550.0
}
},
{
"key_as_string": "2015/03/01 00:00:00",
"key": 1425168000000,
"doc_count": 2,
"the_sum": {
"value": 375.0
},
"the_movfn": {
"value": 305.0
}
}
]
}
}
}

Custom user scripting

移动函数聚合允许用户指定任意脚本来定义自定义逻辑。每次收集新的数据窗口时都会调用脚本。这些值在值变量中提供给脚本。然后脚本应该执行某种计算,并作为结果发出一个double。虽然允许NaN和+/-Inf,但不允许发出null。

例如,此脚本将只返回窗口中的第一个值,如果没有可用值,则返回NaN:

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "return values.length > 0 ? values[0] : Double.NaN"
}
}
}
}
}
}

Pre-built Functions

为了方便起见,已经预先构建了许多函数,这些函数在moving_fn脚本上下文中可用:

  • max()
  • min()
  • sum()
  • stdDev()
  • unweightedAvg()
  • linearWeightedAvg()
  • ewma()
  • holt()
  • holtWinters()

这些函数可从MovingFunctions命名空间中获得。例如 MovingFunctions.max()

max

此函数接受一个doubles集合,并返回该窗口中的最大值。null和NaN值被忽略;最大值仅在实际值上计算。如果窗口为空,或所有值均为null/NaN,则返回NaN作为结果。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_moving_max": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.max(values)"
}
}
}
}
}
}

min

此函数接受一个双精度集合,并返回该窗口中的最小值。null和NaN值被忽略;最小值仅在实际值上计算。如果窗口为空,或所有值均为null/NaN,则返回NaN作为结果。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_moving_min": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.min(values)"
}
}
}
}
}
}

sum

此函数接受一个双精度集合,并返回该窗口中值的总和。null和NaN值被忽略;仅对实际值计算总和。如果窗口为空,或所有值均为空/NaN,则返回0.0作为结果。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_moving_sum": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.sum(values)"
}
}
}
}
}
}

stdDev

此函数接受双精度和平均值的集合,然后返回该窗口中值的标准偏差。null和NaN值被忽略;仅对实际值计算总和。如果窗口为空,或所有值均为空/NaN,则返回0.0作为结果。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_moving_sum": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))"
}
}
}
}
}
}

unweightedAvg

unweightedAvg函数计算窗口中所有值的总和,然后除以窗口的大小。它实际上是窗口的简单算术平均值。简单移动平均值不执行任何时间相关加权,这意味着来自简单移动平均的值往往“滞后”于实际数据。

null和NaN值被忽略;仅对实际值计算平均值。如果窗口为空,或所有值均为null/NaN,则返回NaN作为结果。这意味着平均计算中使用的计数是非空、非NaN值的计数。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.unweightedAvg(values)"
}
}
}
}
}
}

linearWeightedAvg

linearWeightedAvg函数为序列中的点分配一个线性权重,这样“较旧”的数据点(例如,窗口开始处的数据点)对总平均值的贡献线性较小。线性加权有助于减少数据平均值之后的“滞后”,因为旧点的影响较小。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.linearWeightedAvg(values)"
}
}
}
}
}
}

ewma

ewma函数(又称“单指数”)与linearMovAvg函数相似,只是较旧的数据点变得不那么重要,而不是线性地不那么重要。重要性衰减的速度可以通过alpha设置来控制。较小的值会使权重衰减缓慢,从而提供更大的平滑度,并考虑到窗口的较大部分。较大的值会使权重快速衰减,从而减少旧值对移动平均值的影响。这往往会使移动平均线更接近地跟踪数据,但平滑度较低。

null和NaN值被忽略;仅对实际值计算平均值。如果窗口为空,或所有值均为null/NaN,则返回NaN作为结果。这意味着平均计算中使用的计数是非空、非NaN值的计数。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.ewma(values, 0.3)"
}
}
}
}
}
}

holt

霍尔特函数(又名“双指数”)包含了跟踪数据趋势的第二个指数项。当数据具有潜在的线性趋势时,单指数表现不佳。双指数模型内部计算两个值:“水平”和“趋势”。

级别计算类似于ewma,是数据的指数加权视图。不同之处在于,使用了先前平滑的值而不是原始值,从而使其保持接近原始序列。趋势计算着眼于当前值和上次值之间的差异(例如,平滑数据的斜率或趋势)。趋势值也按指数加权。

值通过乘以水平和趋势分量产生。

null和NaN值被忽略;仅对实际值计算平均值。如果窗口为空,或所有值均为null/NaN,则返回NaN作为结果。这意味着平均计算中使用的计数是非空、非NaN值的计数。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "MovingFunctions.holt(values, 0.3, 0.1)"
}
}
}
}
}
}

holtWinters

holtWinters函数(又称“三指数”)包含第三个指数项,它跟踪数据的季节性方面。因此,这种聚合基于三个组成部分:“水平”、“趋势”和“季节性”。

水平和趋势计算与holt相同。季节性计算着眼于当前点和前一个周期点之间的差异。

霍尔特·温特斯(Holt Winters)需要比其他移动平均线多一点的握持。您需要指定数据的“周期性”:例如,如果您的数据每7天有一次周期性趋势,您可以将周期设置为7。同样,如果有月度趋势,您也可以将其设置为30。目前没有周期性检测,但这是为将来的增强而计划的。

null和NaN值被忽略;仅对实际值计算平均值。如果窗口为空,或所有值均为null/NaN,则返回NaN作为结果。这意味着平均计算中使用的计数是非空、非NaN值的计数。

POST /_search
{
"size": 0,
"aggs": {
"my_date_histo":{
"date_histogram":{
"field":"date",
"interval":"1M"
},
"aggs":{
"the_sum":{
"sum":{ "field": "price" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 10,
"script": "if (values.length > 5*2) {MovingFunctions.holtWinters(values, 0.3, 0.1, 0.1, 5, false)}"
}
}
}
}
}
}