时间序列数据的不可变性
作者:Susannah Brodnitz / 产品
2022 年 12 月 14 日
导航至
本文最初发表于 The New Stack,经许可在此处转载。
时间序列数据通常以大量形式出现,需要小心处理才能近乎实时地产生见解。
我们不断地在时间中前进。您阅读这句话所花费的时间现在永远地成为了过去,不可更改。这引出了时间维度数据的独特之处:它只能朝一个方向前进。时间序列数据与其他数据不同,原因有很多。它通常以大量形式出现,需要小心处理才能近乎实时地产生见解。这篇博文重点关注时间序列数据不可更改、不可变的性质。
过去就是过去
在我们的世界中,时间是不可变的,这意味着一旦它成为过去,就无法更改,就像编程中的不可变对象一样。在一个完美的世界中,数据反映了这一点;您无法更改时间序列数据,就像您无法倒转时钟一样。数据应该反映现实,但有时错误的数据点会被写入数据库。错误的数据点也不能反映现实,在这种情况下,删除这些点是有意义的。
删除需要谨慎处理。
- 您需要一个数据库,它可以删除点而不会移动其他点。
- 您可能还需要通过添加延迟到达的点来编辑历史记录。
需要在不断重写过去(以至于数据失去意义)和仍然可以进行必要的更改(以增强时间呈现的上下文)之间取得平衡。当决定是否进行编辑有意义时,请考虑编辑是否使数据更接近反映现实,还是更远离现实。
时间不停流逝
关于时间的另一件事是它永不停息。现在总是不断向前移动。由于时间总是在移动,时间序列数据不断更新。当您想到数据库时,您可能会想到一个存储数据的场所,您可以在其中写入数据,然后在以后读取该数据,而无需经常更改它。时间序列数据库一直在被更改和更新,因为时间总是在移动和变化。
您无法以无限的现实精度收集数据,但您可以选择对您的应用程序有意义的精度级别。例如,平均值是最常见和最有用的计算之一。如果您正在处理非时间序列数据,您可能会平均一个州每平方英里的人数。对于时间序列数据,您可能会平均每小时进入建筑物的人数。这里的不同之处在于,在每个时刻,最后一小时的开始和结束都会发生变化。以下是此类计算的一些示例代码
from(bucket: "sample")
|> range(start: 2022-01-01, stop: 2022-01-31)
|> filter(fn: (r) => r["_measurement"] == "foot_traffic")
|> aggregateWindow(column: "number_of_people",every: 1h, fn: mean, createEmpty: false)
|> yield(name: "running mean")
当您采用移动平均值时,您会在指定的间隔计算一个新的平均值,以便您可以看到计算结果如何随时间变化,从而产生新的时间序列。您需要考虑您的数据集,以了解哪种间隔有意义。如果您选择的间隔太宽,您会丢失信息和上下文,但如果您选择的间隔太精确,您将会有没有数据点的窗口,并且您的结果将以一种没有意义且没有帮助的方式降至零。
时间的上下文
无论您的数据架构多么接近实时,在您的数据被收集并最终进入数据库(准备好被查询)之间,都会存在一些无限小的滞后。如果您设置了自动查询或处理,这可能会使您的结果产生偏差。例如,如果您计算过去五分钟内指标的平均值,则在过去五分钟内到达数据库的数据可能不包括过去五分钟内在边缘采集的全部测量值。InfluxDB 允许您使用 任务偏移来处理这种情况。
您可以安排任务运行此类计算,同时包括一些额外的缓冲时间,以允许所有数据首先到达数据库。这对于保留每个点被收集时的完整上下文非常重要。Telegraf,InfluxData 的开源数据收集代理,也允许偏移。
有很多理由对数据进行降采样。有时您没有足够的存储空间来存储完整的原始数据集。有时,平均信号可以消除噪声,并为您提供更有价值的信息。当您取平均值时,会丢失一些信息,并添加一些新信息。平均值也不是唯一的降采样方法。有时,与其保持数据的形状,不如计算指标超过设定阈值的次数更有意义。
无论您使用哪种降采样方法,您所做的一切都应该是故意的,这样您就不会丢失您后来意识到重要的数据。如果您在降采样时不够小心并且没有正确处理所有时间戳,则降采样可能会使您的时间序列产生偏差。InfluxDB 构建为使用各种工具和流程处理降采样,并且它会在 InfluxDB Cloud 中创建数据的多个备份副本,因此您不会意外删除您需要的点。为了尽可能多地保留上下文,InfluxDB 还支持纳秒级精度。以下是 Flux 中降采样的一些示例代码
from(bucket: "sample")
|> range(start: 2022-01-01, stop: 2022-01-31)
|> filter(fn: (r) => r["_measurement"] == "foot_traffic")
|> aggregateWindow(column: "number_of_people",every: 1h, fn: mean, createEmpty: false)
|> to(bucket: "sample-downsampled")
当然,时间不是唯一需要考虑的重要上下文,时间序列数据也不是唯一重要的数据类型。客户详细信息、位置或正在使用的机器版本等信息不是时间序列数据,但它们对于记录很重要。幸运的是,InfluxDB 允许您将这些其他类型的数据与时间序列数据连接起来,以更深入地了解您的系统和流程。
时间是我们现实世界的基本构建块之一,了解时间的本质有助于您更好地了解世界,并从您的数据中获得更有用的信息。