移动函数聚合
moving_fn
聚合是一种父管道聚合,它在滑动窗口上执行脚本。滑动窗口在一个从父 histogram
或 date histogram
聚合中提取的值序列上移动。窗口每次向右移动一个桶;每次窗口移动时,moving_fn
都会运行脚本。
使用 moving_fn
聚合来对滑动窗口内的数据进行任何数值计算。您可以使用 moving_fn
实现以下目的:
- 趋势分析
- 异常检测
- 自定义时间序列分析
- 自定义平滑算法
- 数字信号处理 (DSP)
参数
moving_fn
聚合接受以下参数。
参数 | 必需/可选 | 数据类型 | 描述 |
---|---|---|---|
buckets_path | 必需 | 字符串 | 包含要处理的度量值的聚合桶路径。参阅桶路径。 |
script(脚本) | 必需 | 字符串或对象 | 计算每个数据窗口值的脚本。可以是内联脚本、存储脚本或脚本文件。脚本可以访问 buckets_path 参数中定义的变量名。 |
window | 必需 | 整数 | 滑动窗口中的桶数量。必须是正整数。 |
gap_policy | 可选 | 字符串 | 应用于缺失数据的策略。有效值为 skip 和 insert_zeros 。默认值为 skip 。参阅数据间隙。 |
format | 可选 | 字符串 | 一个 DecimalFormat 格式化字符串。在聚合的 value_as_string 属性中返回格式化的输出。 |
shift | 可选 | 整数 | 窗口移动的桶数量。可以是正数(向右移动到未来桶)或负数(向左移动到过去桶)。默认值为 0 ,将窗口直接置于当前桶的左侧。参阅移动窗口。 |
移动函数如何工作
moving_fn
聚合在有序桶序列的滑动窗口上操作。从父聚合的第一个桶开始,moving_fn
执行以下操作:
- 从
window
和shift
参数指定的桶中收集子序列(窗口)的值。 - 将这些值作为数组传递给
script
指定的函数。 - 使用
script
从数组中计算单个值。 - 将此值作为当前桶的结果返回。
- 向前移动一个桶并重复此过程。
“过去”和“未来”值指的是时间序列数据,这是移动窗口函数最常见的用例。更一般地,它们分别指的是任何有序数据序列中的前一个值和即将到来的值。
moving_fn
应用的脚本可以是预定义函数或自定义脚本。桶值以 values
数组的形式提供给脚本。脚本返回一个双精度值作为结果。允许结果值为 NaN
和 +/- Inf
,但不允许 null
。
窗口大小
window
参数指定定义窗口大小的桶数量。
传递给 script
函数的数组是零索引的。其值在脚本中通过 values[0]
到 values[n]
访问,其中 n = values.length - 1
。
移动窗口
shift
参数控制移动窗口相对于当前桶的位置。根据您的分析是否需要历史上下文、当前数据或未来预测来设置 shift
。默认值为 0
,这只显示过去的值(不包括当前桶)。
shift
的一些常用值如下:
shift | 窗口描述 | |
---|---|---|
0 | 仅过去的值。不包括当前值。 | --[-----]x---- |
1 | 过去的值,包括当前值。 | --[----x]----- |
窗口/2 | 将窗口中心置于当前值周围。 | --[--x--]----- |
window | 未来值,包括当前值。 | --[x----]----- |
当窗口在序列的开始或结束处超出可用数据时,window
会自动缩小以仅使用可用点。
[x----]--
-[x----]-
--[x----]
---[x---]
----[x--]
-----[x-]
------[x]
预定义函数
moving_fn
聚合支持许多预定义函数,这些函数可以代替自定义脚本使用。这些函数可以通过 MovingFunctions
上下文访问。例如,您可以将 max
函数作为 MovingFunctions.max(values)
访问。
下表描述了预定义函数。
功能 | 模型关键词 | 描述 |
---|---|---|
最大值 | max | 窗口中的最大值。 |
最小值 | min | 窗口中的最小值。 |
总和 | sum | 窗口中值的总和。 |
非加权平均值 | unweightedAvg | 窗口中所有值的非加权平均值,等于 sum / window 。 |
线性加权平均 | linearWeightedAvg | 使用线性衰减权重进行加权平均,更加重视近期值。 |
指数加权移动平均 | ewma | 使用指数衰减权重进行加权平均,更加重视近期值。 |
Holt | holt | 使用第二个指数项来平滑长期趋势的加权平均。 |
Holt-Winters | holt_winters | 使用第三个指数项来平滑周期(季节性)效应的加权平均。 |
标准差 | stdDev | 窗口中值的总和。 |
所有预定义函数都将 values
数组作为它们的第一个参数。对于接受额外参数的函数,请在 values
之后按顺序传递这些参数。例如,通过将 script
值设置为 MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))
来调用 stdDev
函数。
下表显示了每个模型所需的设置。
功能 | 额外参数 | 允许值 | 默认值 | 描述 |
---|---|---|---|---|
max | 无 | 数字数组 | 无 | 窗口的最大值。 |
min | 无 | 数字数组 | 无 | 窗口的最小值。 |
sum | 无 | 数字数组 | 无 | 窗口中所有值的总和。 |
unweightedAvg | 无 | 数字数组 | 无 | 窗口中所有值的算术平均值。 |
linearWeightedAvg | 无 | 数字数组 | 无 | 窗口中所有值的加权平均值,其中近期值权重更高。 |
ewma | alpha | [0, 1] | 0.3 | 衰减参数。值越高,近期数据点的权重越大。 |
holt | alpha | [0, 1] | 0.3 | 水平分量的衰减参数。 |
beta | [0, 1] | 0.1 | 趋势分量的衰减参数。 | |
holt_winters | alpha | [0, 1] | 0.3 | 水平分量的衰减参数。 |
beta | [0, 1] | 0.3 | 趋势分量的衰减参数。 | |
gamma | [0, 1] | 0.3 | 季节性分量的衰减参数。 | |
type | add , mult | add | 定义季节性如何建模:加法或乘法。 | |
period | 整数 | 1 | 构成周期的桶数量。 | |
pad | 布尔型 | true | 是否为 mult 类型模型中的 0 值添加一个小偏移量,以避免除以零错误。 | |
stdDev | avg | 任意双精度值 | 无 | 窗口的标准差。要计算有意义的标准差,请使用滑动窗口数组的均值,通常是 MovingFunctions.unweightedAvg(values) 。 |
预定义函数不支持缺少参数的函数签名。因此,您必须提供额外参数,即使使用默认值也是如此。
示例:预定义函数
以下示例使用 OpenSearch Dashboards 日志样本数据创建了一个以一周为间隔的日期直方图。sum
子聚合计算每周记录的所有字节的总和。最后,moving_fn
聚合计算字节总和的标准差,使用 5
的 window
大小、默认 0
的 shift
和非加权平均值。
POST /opensearch_dashboards_sample_data_logs/_search
{
"size": 0,
"aggs": {
"my_date_histo": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "week"
},
"aggs": {
"the_sum": {
"sum": { "field": "bytes" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 5,
"script": "MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))"
}
}
}
}
}
}
示例响应
响应显示从第二个桶中的零值开始的移动窗口的标准差。stdDev
函数对于空窗口或仅包含无效值(null
或 NaN
)的窗口返回 0
。
响应
{
"took": 15,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 10000,
"relation": "gte"
},
"max_score": null,
"hits": []
},
"aggregations": {
"my_date_histo": {
"buckets": [
{
"key_as_string": "2025-03-24T00:00:00.000Z",
"key": 1742774400000,
"doc_count": 249,
"the_sum": {
"value": 1531493
},
"the_movavg": {
"value": null
}
},
{
"key_as_string": "2025-03-31T00:00:00.000Z",
"key": 1743379200000,
"doc_count": 1617,
"the_sum": {
"value": 9213161
},
"the_movavg": {
"value": 0
}
},
{
"key_as_string": "2025-04-07T00:00:00.000Z",
"key": 1743984000000,
"doc_count": 1610,
"the_sum": {
"value": 9188671
},
"the_movavg": {
"value": 3840834
}
},
{
"key_as_string": "2025-04-14T00:00:00.000Z",
"key": 1744588800000,
"doc_count": 1610,
"the_sum": {
"value": 9244851
},
"the_movavg": {
"value": 3615414.498228507
}
},
{
"key_as_string": "2025-04-21T00:00:00.000Z",
"key": 1745193600000,
"doc_count": 1609,
"the_sum": {
"value": 9061045
},
"the_movavg": {
"value": 3327358.65618917
}
},
{
"key_as_string": "2025-04-28T00:00:00.000Z",
"key": 1745798400000,
"doc_count": 1554,
"the_sum": {
"value": 8713507
},
"the_movavg": {
"value": 3058812.9440705855
}
},
{
"key_as_string": "2025-05-05T00:00:00.000Z",
"key": 1746403200000,
"doc_count": 1710,
"the_sum": {
"value": 9544718
},
"the_movavg": {
"value": 195603.33146038183
}
},
{
"key_as_string": "2025-05-12T00:00:00.000Z",
"key": 1747008000000,
"doc_count": 1610,
"the_sum": {
"value": 9155820
},
"the_movavg": {
"value": 270085.92336040025
}
},
{
"key_as_string": "2025-05-19T00:00:00.000Z",
"key": 1747612800000,
"doc_count": 1610,
"the_sum": {
"value": 9025078
},
"the_movavg": {
"value": 269477.75659701484
}
},
{
"key_as_string": "2025-05-26T00:00:00.000Z",
"key": 1748217600000,
"doc_count": 895,
"the_sum": {
"value": 5047345
},
"the_movavg": {
"value": 267356.5422566652
}
}
]
}
}
}
自定义脚本
您可以提供任意自定义脚本来计算 moving_fn
结果。自定义脚本使用 Painless 脚本语言。
示例:自定义脚本
以下示例使用 OpenSearch Dashboards 电子商务样本数据创建了一个以一周为间隔的日期直方图。sum
子聚合计算每周所有应税收入的总和。然后,moving_fn
脚本返回当前值前两个值中的较大者,如果这两个值不可用则返回 NaN
。
POST /opensearch_dashboards_sample_data_ecommerce/_search
{
"size": 0,
"aggs": {
"my_date_histo": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "week"
},
"aggs": {
"the_sum": {
"sum": { "field": "taxful_total_price" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 2,
"script": "return (values.length < 2 ? Double.NaN : (values[0]>values[1] ? values[0] : values[1]))"
}
}
}
}
}
}
示例返回从第三个桶开始的计算结果,该桶有足够的先前数据来执行计算。
响应
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4675,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"my_date_histo": {
"buckets": [
{
"key_as_string": "2025-03-24T00:00:00.000Z",
"key": 1742774400000,
"doc_count": 582,
"the_sum": {
"value": 41455.5390625
},
"the_movavg": {
"value": null
}
},
{
"key_as_string": "2025-03-31T00:00:00.000Z",
"key": 1743379200000,
"doc_count": 1048,
"the_sum": {
"value": 79448.60546875
},
"the_movavg": {
"value": null
}
},
{
"key_as_string": "2025-04-07T00:00:00.000Z",
"key": 1743984000000,
"doc_count": 1048,
"the_sum": {
"value": 78208.4296875
},
"the_movavg": {
"value": 79448.60546875
}
},
{
"key_as_string": "2025-04-14T00:00:00.000Z",
"key": 1744588800000,
"doc_count": 1073,
"the_sum": {
"value": 81277.296875
},
"the_movavg": {
"value": 79448.60546875
}
},
{
"key_as_string": "2025-04-21T00:00:00.000Z",
"key": 1745193600000,
"doc_count": 924,
"the_sum": {
"value": 70494.2578125
},
"the_movavg": {
"value": 81277.296875
}
}
]
}
}
}
示例:移动平均
moving_fn
聚合取代了已弃用的 moving_avg
聚合。moving_fn
聚合类似于 moving_avg
聚合,但功能更强大,因为它计算任意函数而不仅仅是平均值。所有预定义的 moving_avg
函数也都在 moving_fn
中实现。
holt
模型是一种移动平均,它使用由 alpha
和 beta
参数控制的指数衰减权重。以下示例使用 OpenSearch Dashboards 日志样本数据创建了一个以一周为间隔的日期直方图。sum
子聚合计算每周所有字节的总和。最后,moving_fn
聚合使用 Holt 模型计算字节总和的加权平均值,其中 window
大小为 6
,默认 shift
为 0
,alpha
值为 0.3
,beta
值为 0.1
。
POST /opensearch_dashboards_sample_data_logs/_search
{
"size": 0,
"aggs": {
"my_date_histogram": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "week"
},
"aggs": {
"the_sum": {
"sum": { "field": "bytes" }
},
"the_movavg": {
"moving_fn": {
"buckets_path": "the_sum",
"window": 6,
"script": "MovingFunctions.holt(values, 0.3, 0.1)"
}
}
}
}
}
}
聚合返回从第二个桶开始的移动 holt
平均值。
响应
{
"took": 16,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 10000,
"relation": "gte"
},
"max_score": null,
"hits": []
},
"aggregations": {
"my_date_histogram": {
"buckets": [
{
"key_as_string": "2025-03-24T00:00:00.000Z",
"key": 1742774400000,
"doc_count": 249,
"the_sum": {
"value": 1531493
},
"the_movavg": {
"value": null
}
},
{
"key_as_string": "2025-03-31T00:00:00.000Z",
"key": 1743379200000,
"doc_count": 1617,
"the_sum": {
"value": 9213161
},
"the_movavg": {
"value": 1531493
}
},
{
"key_as_string": "2025-04-07T00:00:00.000Z",
"key": 1743984000000,
"doc_count": 1610,
"the_sum": {
"value": 9188671
},
"the_movavg": {
"value": 3835993.3999999994
}
},
{
"key_as_string": "2025-04-14T00:00:00.000Z",
"key": 1744588800000,
"doc_count": 1610,
"the_sum": {
"value": 9244851
},
"the_movavg": {
"value": 5603111.707999999
}
},
{
"key_as_string": "2025-04-21T00:00:00.000Z",
"key": 1745193600000,
"doc_count": 1609,
"the_sum": {
"value": 9061045
},
"the_movavg": {
"value": 6964515.302359998
}
},
{
"key_as_string": "2025-04-28T00:00:00.000Z",
"key": 1745798400000,
"doc_count": 1554,
"the_sum": {
"value": 8713507
},
"the_movavg": {
"value": 7930766.089341199
}
},
{
"key_as_string": "2025-05-05T00:00:00.000Z",
"key": 1746403200000,
"doc_count": 1710,
"the_sum": {
"value": 9544718
},
"the_movavg": {
"value": 8536788.607547803
}
},
{
"key_as_string": "2025-05-12T00:00:00.000Z",
"key": 1747008000000,
"doc_count": 1610,
"the_sum": {
"value": 9155820
},
"the_movavg": {
"value": 9172269.837272028
}
},
{
"key_as_string": "2025-05-19T00:00:00.000Z",
"key": 1747612800000,
"doc_count": 1610,
"the_sum": {
"value": 9025078
},
"the_movavg": {
"value": 9166173.88436614
}
},
{
"key_as_string": "2025-05-26T00:00:00.000Z",
"key": 1748217600000,
"doc_count": 895,
"the_sum": {
"value": 5047345
},
"the_movavg": {
"value": 9123157.830417283
}
}
]
}
}
}