移动函数聚合

编辑

对于有序的数据序列,移动函数聚合会在数据上滑动窗口,并允许用户指定在每个数据窗口上执行的自定义脚本。为了方便起见,预定义了许多常用函数,例如最小值/最大值、移动平均等。

语法

编辑

一个 moving_fn 聚合的独立形式如下所示

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

表 66. moving_fn 参数

参数名 描述 必需 默认值

buckets_path

要关注的指标的路径(有关更多详细信息,请参阅 buckets_path 语法

必需

window

在直方图上“滑动”的窗口大小。

必需

script

应在每个数据窗口上执行的脚本

必需

gap_policy

当在数据中发现缺口时应用的策略。 请参阅处理数据中的缺口

可选

skip

shift

窗口位置的偏移量

可选

0

moving_fn 聚合必须嵌入在 histogramdate_histogram 聚合内部。它们可以像任何其他指标聚合一样嵌入。

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movfn": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.unweightedAvg(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movfn: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.unweightedAvg(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movfn: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.unweightedAvg(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {                  
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }   
        },
        "the_movfn": {
          "moving_fn": {
            "buckets_path": "the_sum",  
            "window": 10,
            "script": "MovingFunctions.unweightedAvg(values)"
          }
        }
      }
    }
  }
}

在 “timestamp” 字段上构建了一个名为“my_date_histo”的 date_histogram,时间间隔为一个月。

使用 sum 指标来计算字段的总和。这可以是任何数值指标(sum、min、max 等)

最后,我们指定一个使用 “the_sum” 指标作为输入的 moving_fn 聚合。

通过首先在某个字段上指定一个 histogramdate_histogram 来构建移动平均值。然后,您可以选择在该直方图内添加数值指标,例如 sum。最后,将 moving_fn 嵌入到直方图中。buckets_path 参数用于“指向”直方图内的同级指标之一(有关 buckets_path 语法的说明,请参阅 buckets_path 语法)。

以上聚合的示例响应可能如下所示

{
   "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
                 }
             }
         ]
      }
   }
}

自定义用户脚本

编辑

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

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

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_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"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'return values.length > 0 ? values[0] : Double.NaN'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_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",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_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"
          }
        }
      }
    }
  }
}

shift 参数

编辑

默认情况下(shift = 0),用于计算的窗口是最后 n 个值,不包括当前桶。将 shift 增加 1 会将起始窗口位置向右移动 1

  • 要将当前桶包含到窗口中,请使用 shift = 1
  • 对于中心对齐(当前桶之前和之后的 n / 2 个值),请使用 shift = window / 2
  • 对于右对齐(当前桶之后的 n 个值),请使用 shift = window

如果任何一个窗口边缘移动到数据序列的边界之外,则窗口会缩小到仅包含可用值。

预构建函数

编辑

为了方便起见,预构建了许多函数,并且可以在 moving_fn 脚本上下文中可用

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

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

max 函数

编辑

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

表 67. max(double[] values) 参数

参数名 描述

values

要查找最大值的窗口

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_moving_max": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.max(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_max: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.max(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_moving_max: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.max(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_moving_max": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.max(values)"
          }
        }
      }
    }
  }
}

min 函数

编辑

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

表 68. min(double[] values) 参数

参数名 描述

values

要查找最小值的窗口

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_moving_min": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.min(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_min: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.min(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_moving_min: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.min(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_moving_min": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.min(values)"
          }
        }
      }
    }
  }
}

sum 函数

编辑

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

表 69. sum(double[] values) 参数

参数名 描述

values

要查找总和的值的窗口

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_moving_sum": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.sum(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_sum: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.sum(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_moving_sum: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.sum(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_moving_sum": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.sum(values)"
          }
        }
      }
    }
  }
}

stdDev 函数

编辑

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

表 70. stdDev(double[] values) 参数

参数名 描述

values

要查找标准偏差的值的窗口

avg

窗口的平均值

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_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))"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_moving_sum: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_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))",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_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))"
          }
        }
      }
    }
  }
}

必须将 avg 参数提供给标准偏差函数,因为可以在窗口上计算不同风格的平均值(简单、线性加权等)。以下详细介绍的各种移动平均值可用于计算标准偏差函数的平均值。

unweightedAvg 函数

编辑

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

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

表 71. unweightedAvg(double[] values) 参数

参数名 描述

values

要查找总和的值的窗口

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.unweightedAvg(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.unweightedAvg(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.unweightedAvg(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_interval": "1M"
      },
      "aggs": {
        "the_sum": {
          "sum": { "field": "price" }
        },
        "the_movavg": {
          "moving_fn": {
            "buckets_path": "the_sum",
            "window": 10,
            "script": "MovingFunctions.unweightedAvg(values)"
          }
        }
      }
    }
  }
}

linearWeightedAvg 函数

编辑

linearWeightedAvg 函数为序列中的点分配线性加权,使得“较旧”的数据点(例如窗口开头的那些数据点)对总平均值的贡献线性减少。线性加权有助于减少数据平均值后面的“滞后”,因为较旧的点的影响较小。

如果窗口为空,或者所有值均为 null/NaN,则返回 NaN 作为结果。

表 72. linearWeightedAvg(double[] values) 参数

参数名 描述

values

要查找总和的值的窗口

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.linearWeightedAvg(values)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.linearWeightedAvg(values)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.linearWeightedAvg(values)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_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 设置来控制重要性衰减的速度。小值会使权重衰减缓慢,从而提供更大的平滑度并考虑窗口的较大部分。较大的值会使权重快速衰减,从而减少较旧的值对移动平均值的影响。这往往会使移动平均值更紧密地跟踪数据,但平滑度较低。

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

表 73. ewma(double[] values, double alpha) 参数

参数名 描述

values

要查找总和的值的窗口

alpha

指数衰减

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_interval": "1M"
            },
            "aggs": {
                "the_sum": {
                    "sum": {
                        "field": "price"
                    }
                },
                "the_movavg": {
                    "moving_fn": {
                        "buckets_path": "the_sum",
                        "window": 10,
                        "script": "MovingFunctions.ewma(values, 0.3)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.ewma(values, 0.3)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_interval: "1M",
      },
      aggs: {
        the_sum: {
          sum: {
            field: "price",
          },
        },
        the_movavg: {
          moving_fn: {
            buckets_path: "the_sum",
            window: 10,
            script: "MovingFunctions.ewma(values, 0.3)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_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 函数

编辑

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

水平计算类似于 ewma,并且是数据的指数加权视图。不同之处在于使用先前平滑的值而不是原始值,这使其能够保持接近原始序列。趋势计算查看当前值和最后一个值之间的差异(例如,平滑数据的斜率或趋势)。趋势值也采用指数加权。

通过将水平和趋势分量相乘来生成值。

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

表 74. holt(double[] values, double alpha) 参数

参数名 描述

values

要查找总和的值的窗口

alpha

水平衰减值

beta

趋势衰减值

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_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)"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          the_sum: {
            sum: {
              field: 'price'
            }
          },
          the_movavg: {
            moving_fn: {
              buckets_path: 'the_sum',
              window: 10,
              script: 'MovingFunctions.holt(values, 0.3, 0.1)'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_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)",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_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)"
          }
        }
      }
    }
  }
}

实际上,alpha 值在 holtMovAvg 中的行为与 ewmaMovAvg 非常相似:较小的值会产生更多的平滑和更多滞后,而较大的值会产生更紧密的跟踪和更少的滞后。通常很难看到 beta 的值。较小的值强调长期趋势(例如整个序列中的恒定线性趋势),而较大的值强调短期趋势。

holtWinters 函数

编辑

holtWinters 函数(又名“三指数”)包含跟踪数据季节性方面的第三个指数项。因此,此聚合会根据三个分量进行平滑:“水平”、“趋势”和“季节性”。

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

相比其他移动平均算法,Holt-Winters 需要更多的手动配置。你需要指定数据的“周期性”:例如,如果你的数据每 7 天呈现循环趋势,你应该设置 period = 7。同样,如果存在每月趋势,则应将其设置为 30。目前还没有周期性检测功能,但这已计划在未来的增强功能中实现。

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

表 75. holtWinters(double[] values, double alpha) 参数

参数名 描述

values

要查找总和的值的窗口

alpha

水平衰减值

beta

趋势衰减值

gamma

季节性衰减值

period

数据的周期性

multiplicative

如果希望使用乘法 Holt-Winters,则为 True;如果使用加法,则为 False

resp = client.search(
    size=0,
    aggs={
        "my_date_histo": {
            "date_histogram": {
                "field": "date",
                "calendar_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)}"
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  body: {
    size: 0,
    aggregations: {
      my_date_histo: {
        date_histogram: {
          field: 'date',
          calendar_interval: '1M'
        },
        aggregations: {
          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)}'
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  size: 0,
  aggs: {
    my_date_histo: {
      date_histogram: {
        field: "date",
        calendar_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)}",
          },
        },
      },
    },
  },
});
console.log(response);
POST /_search
{
  "size": 0,
  "aggs": {
    "my_date_histo": {
      "date_histogram": {
        "field": "date",
        "calendar_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)}"
          }
        }
      }
    }
  }
}

乘法 Holt-Winters 的工作原理是将每个数据点除以季节性值。如果你的任何数据为零,或者数据中存在空白(因为这会导致除以零),则会出现问题。为了解决这个问题,mult Holt-Winters 会用一个非常小的量 (1*10-10) 填充所有值,以便所有值都为非零值。这会影响结果,但影响很小。如果你的数据为非零值,或者你更希望在遇到零时看到 NaN,你可以使用 pad: false 来禁用此行为。

“冷启动”

编辑

遗憾的是,由于 Holt-Winters 的特性,它需要两个周期的数据来“引导”算法。这意味着你的 window 必须始终 至少 是周期的两倍大小。如果不是,则会抛出异常。这也意味着 Holt-Winters 不会为前 2 * period 个桶发出值;当前算法不进行回溯。

你会在上面的示例中注意到我们有一个 if () 语句检查值的大小。这是为了确保我们在调用 holt-winters 函数之前有足够两个周期的数据(5 * 2,其中 5 是 holtWintersMovAvg 函数中指定的周期)。