本文介绍 SonnetDB 的 moving_average() 与 ewma(),重点是窗口如何移动、缺失值如何参与,以及参数与时间间隔的关系。
平滑可以让趋势更容易观察,但也可能压低短时尖峰。使用前应保留原始序列,并用自己的报警目标评估响应延迟;不能仅因为曲线更平滑,就认定异常检测质量提高。
moving_average 按最近 N 行移动
moving_average(field, n)的 n 是正整数行数,不是秒数,也不是“最近 N 个有效值”。当前实现为每一行推进一个环形槽位;缺失行会占用窗口位置,但不计入平均数的分母。
前 n-1 行输出 NULL。达到 n 行后,如果最近 n 行中至少有一个有效数值,就输出这些有效值的平均;全缺失窗口输出 NULL。
例如 n=3,输入 1、NULL、5 时,第三行得到 (1+5)/2=3,而不必等待第三个有效样本。下一行到来时,最早一行照常退出窗口。这是按实现定义的手算示例。
SELECTtime,temperature,moving_average(temperature,3)ASaverage_3_rows,ewma(temperature,0.3)ASweighted_valueFROMsensorsWHEREdevice='thermo-05'ANDtime>=1700000000000ANDtime<1700003600000ORDERBYtime;示例假设 sensors 已有 device TAG 与 temperature FIELD FLOAT。
ewma 的状态与缺失值
ewma(field, alpha)按s = alpha × 当前值 + (1-alpha) × 上一平滑值更新,alpha 取 (0,1]。首个有效值直接作为初始平滑值。
缺失值不更新状态:初始化前输出 NULL,初始化后继续输出上一平滑值。alpha=1 时,有效行跟随当前值,但缺失行仍保留已有状态,不能将这一情形等同于无条件复制原始列。
alpha 较大时当前值权重较高;较小时历史权重衰减较慢。它不自动计算采样时间差,同样的 alpha 在不同采样频率下代表不同的物理响应速度。
选择参数时保留时间语义
moving_average 的窗口按行数推进,ewma 按有效样本更新;两者都没有把时间戳用于时间加权。采样间距不齐时,“最近 10 行”不等于“最近 10 秒”。需要先按时间分桶或明确缺口策略,再比较平滑结果。
从当前状态结构看,移动平均保存与 n 成比例的窗口数据,ewma 保存常数数量的平滑状态;这是状态结构说明,不是整个查询内存、吞吐或生产延迟的实测结论。
本文依据 2026-10-15 当前源码复核;SQL 为复现示例,本轮未执行数据库、模型或性能测试。封面曲线仅说明平滑概念,不是 SonnetDB 实测结果。
依据:SmoothingFunctions.cs 与 WindowFunctionBinder.cs。