滑动窗口

由于 流视图 是实时增量更新的,PipelineDB可以在更新流视图结果集时考虑当前时间。WHERE 子句中包含与 当前时间 相关信息的查询被称作 滑动窗口查询。滑动的 WHERE 子句过滤或接收到的 event 集合是随时间持续变化的。

滑动 WHERE 子句包含两个重要元素:

clock_timestamp ( )

内置函数,总返回当前时间戳。

arrival_timestamp

event 的特殊属性,它包含 PipelineDB接收数据的时间,在 Arrival Ordering 中有详细描述。

然而,我们无须显式添加 WHERE 子句来引用这些值,PipelineDB已经在内部执行了,我们在定义流视图时指定 sw 存储参数即可。

下面的例子可以很好地阐明这些概念。

示例

即使滑动窗口对SQL数据库来说是一个新概念,PipelineDB没有引入任何新的或特有的窗口语法,而是使用PostgreSQL 9.5的标准语法,如下所示:

最近一分钟的用户

CREATE VIEW recent_users WITH (sw = '1 minute') AS
   SELECT user_id::integer FROM stream;

可以通过如下SQL实现相同的逻辑:

CREATE VIEW recent_users AS
   SELECT user_id::integer FROM stream
WHERE (arrival_timestamp > clock_timestamp() - interval '1 minute');

注解

尽管 sw 显得更加简洁,PipelineDB仍然允许用户通过 WHERE 手动构造基于滑动窗口的流视图。

上面的流视图只会包含最后一分钟的用户。也就是说,即使流视图中的数据没有更新,每次 SELECT 查询仍然会返回不同的结果,

让我们对 (arrival_timestamp > clock_timestamp() - interval '1 minute') 语句进行分解。

clock_timestamp() - interval '1 minute' 每次执行时,它将返回一分钟前的时间戳。如果 arrival_timestamp 大于一分钟前的时间, arrival_timestamp and > 将返回 true。由于每次读取到新的 event 时这个不等式都会被执行,所以窗口中总是维系着最近一分钟的数据。

注解

虽然PipelineDB曝露了 current_datecurrent_time`以及 :code:`current_timestamp 来配合查询使用,但他们不是被设计用于滑动窗口的,因为他们在一次事务中是常量,所以不能准备地表示当前时间。

滑动聚合

滑动窗口也同聚合函数一起使用。滑动聚合可以尽可能地聚合输入数据,但不会随时间演进而丢失用于维系窗口的粒度。这部分聚合函数对用户是完全透明的,只有滑动聚合后的结果才对用户可见。

让我们来看看下面的例子:

最近一分钟的用户日志数

CREATE VIEW count_recent_users WITH (sw = '1 minute') AS
   SELECT COUNT(*) FROM stream;

流视图中的 SELECT 每次执行时,count 只会返回最近一分钟的计数。如果没有新数据写入,count 的值会随着流视图的计算而越来越小。滑动窗口以用于PipelineDB支持的所有 流聚合 函数中。

传感器近5分钟的平均温度

CREATE VIEW sensor_temps WITH (sw = '5 minutes') AS
   SELECT sensor::integer, AVG(temp::numeric) FROM sensor_stream
GROUP BY sensor;

近30天的去重用户数

CREATE VIEW uniques WITH (sw = '30 days') AS
   SELECT COUNT(DISTINCT user::integer) FROM user_stream;

服务器近5分钟延时的99分位数

CREATE VIEW latency WITH (sw = '5 minutes') AS
   SELECT server_id::integer, percentile_cont(0.99)
   WITHIN GROUP (ORDER BY latency::numeric) FROM server_stream
GROUP BY server_id;

时间失效

显然,流视图中的窗口期数据会在一段时间后失效,因为这些数据的时间已经小于窗口的下限。这些数据可以通过两种方式被 垃圾回收

Background invalidation

一个类似于PostgreSQL中 autovacuumer 的后台进程周期性地对基于滑动窗口的流视图中的过期数据执行物理删除。

Read-time invalidation

当通过 SELECT 读取流视图时,过期数据会在新数据产生时被 丢弃 。这样可以保证无效数据即使 存在 也不会被查询到。

注解

译者注:根据本人粗浅的理解,上面原文中的 丢弃存在 分别代表 逻辑删除未被物理删除,上面的 Read-time invalidationBackground invalidation 是相互配置来进行GC的,Read-time invalidation 先逻辑删除,然后 Background invalidation 执行物理删除。


step_factor

支持滑动窗口查询的物化表会在内部尽可能聚合数据。然而,查询的粒度不能与原始数据的粒度一致,因为数据在超出窗口后会被移除。

比如,一个基于小时的滑动窗口查询可能是由磁盘中分钟级别的数据聚合而成的,以便最近60分钟的数据都包含在最终返回给用户的聚合结果中。也就是说,用户滑动窗口查询的更小粒度的聚合等级被称作 stepsoverlay 视图位于这些 steps 聚合中,以便更“平滑”地获取最终的聚合结果。

您可能已经注意到 step 聚合是影响滑动窗口查询性能的重要因素,因为每个滑动窗口聚合的分组内部都是由一系列 steps 组成的。 每个滑动窗口聚合的分组所包含的 stpes 的数量可以通过 step_factor 参数配置:

step_factor

可以通过1~50的整数来指定滑动窗口 step 长度相对于 sw 窗口的百分比。step_factor 越小,数据离开窗口的时间精度就越高,物化表的磁盘开销越大。step_factor 越大,数据离开窗口的时间精度就越低,物化表的磁盘开销越小。

注解

译者注:一言以蔽之,step 即滑动步长,step_factor 即滑动步长相对窗口长度的百分比。

下面例子将 step_factor 结合 sw 使用,将1小时窗口长度的 step 设置为30分钟:

CREATE VIEW hourly (WITH sw = '1 hour', step_factor = 50)
  AS SELECT COUNT(*) FROM stream;

滑动窗口介绍完毕,现在是时候看看 流关联 了。