【Flink Scala】Table API 和SQL中的窗口

窗口

Group Windows

Group Windows是使用 window(w:GroupWindow)子句定义的,并且必须由as子句指定一个别名。

为了按窗口对表进行分组,窗口的别名必须在 group by 子句中,像常规的分组字段一样引用

Table table = input
	.window([w: GroupWindow] as "w") // 定义窗口,别名为 w
	.groupBy("w, a") // 按照字段 a和窗口 w分组
	.select("a, b.sum"); // 聚合

select语句中,我们除了可以获取到数据元素以外,还可以获取到窗口的元数据信息。

Table table = input
    .window([w:Window] as "window") // 
    .groupBy("window" , "id") // 根据窗口聚合,窗口数据分配到每单个Task算子
    .select("id" , "var1.sum","window.start","window.end","window.rowtime") // 指定val字段求和

跳转顶部


Tumbling Windows

前面提到滚动窗口的窗口长度是固定的,窗口之间的数据不会重合。滚动窗口可以基于Evenet TimeProcess Time以及Row-Count来定义。如下实例:Table API中滚动窗口使用Tumble Class来创建,且分别基于Evenet TimeProcess Time以及Row-Count来定义窗口。

// 通过scan方法在CataLog中查询Sensors表
tableEnv.scan("Sensors")
    // 十分钟事件语义下的滚动窗口
    .window(Tumble.over("10.minutes").on("rowtime").as("w"));
    // 十分钟过程语义下的滚动窗口
    .window(Tumble.over("10.minutes").on("proctime").as("w"));
    // 十行过程语义下的滚动窗口
    .window(Tumble.over("10.rows").on("proctime").as("w"));
  • over: 指定窗口的长度

  • on : 定义了窗口基于的时间概念类型为EventTime还是ProcessTimeEventTime对应着rowtime
    ProcessTime对应着proctime

  • as : 将创建的窗口重命名,同时窗口名称需要在后续的孙子中使用

实际案例

    val resultTable = sensorTable
      .window(Tumble over 10.seconds on 'ts as 'tw) //每十秒统计一次,滚动窗口
      .groupBy('id, 'tw)
      .select('id, 'id.count, 'temperature.avg, 'tw.end) //end是当前窗口的结束时间

跳转顶部


Sliding Windows

滑动窗口的长度也是固定的,但窗口与窗口之间的数据能够重合。滑动窗口可以基于Evenet TimeProcess Time以及Row-Count来定义。如下实例:Table API中滑动窗口使用Slide Class来创建,且分别基于Evenet TimeProcess Time以及Row-Count来定义窗口。

// 通过scan方法在CataLog中查询Sensors表
tableEnv.scan("Sensors")
    .window(Slide.over("10.minutes").every("5.minutes").on("rowtime").as("w"));
    .window(Slide.over("10.minutes").every("5.minutes").on("proctime").as("w"));
    .window(Slide.over("10.rows").every("5.rows").on("proctime").as("w"));
  • over: 定义窗口的长度,可以是时间或行计数间隔。

  • every : 定义滑动间隔,可以是时间间隔也可以是行数。滑动间隔必须与大小间隔的类型相同。

  • on : 定义了窗口基于的时间概念类型为EventTime还是ProcessTimeEventTime对应着rowtimeProcessTime对应着proctime

  • as: 将创建的窗口重命名,同时窗口名称需要在后续的孙子中使用。

跳转顶部


Session Windows

Tumbling、Sliding窗口不同的是,Session窗口不需要指定固定的窗口时间,而是通过判断固定时间内数据的活跃性来切分窗口。例如 10 min内数据不接入则切分窗口并触发计算。Session窗口只能基于EventTimeProcessTime时间概念来定义,通过withGrap操作符指定数据不活跃的时间Grap,表示超过该时间数据不接入,则切分窗口并触发计算。

tableEnv.scan("Sensors")
    .window(Session.withGap("10.minutes").on("rowtime").as("w"));
    .window(Session.withGap("10.minutes").on("proctime").as("w"));

跳转顶部


Over Windows

Over Window和标准SQL中提供的Over语法功能类似,也是一种数据聚合计算的方式,但和Group Window不同的是,Over Window不需要对输入数据按照窗口大小进行堆叠。Over Window是基于当前数据和其周围邻近范围内数据进行聚合统计的,例如基于当前记录前面的20条数据,然后基于这些数据统计某一指标的聚合结果。

Table API中,Over Window也是在window方法中指定,但后面不需要和groupBy操作符绑定,后面直接接SELECT操作符,并在select操作符中指定需要查询字段和聚合指标。

Table table = input
.window([w: OverWindow] as "w")
.select("a, b.sum over w, c.min over w");

无界Over Windows

  • 可以在事件时间或处理时间,以及指定为时间间隔、或行计数的范围内,定义 Over windows

  • 无界的 over window是使用常量指定的

// 无界的事件时间 over window
.window(Over.partitionBy("a").orderBy("rowtime").preceding(UNBOUNDED_RANGE).as("w"))
//无界的处理时间 over window
.window(Over.partitionBy("a").orderBy("proctime").preceding(UNBOUNDED_RANGE).as("w"))
// 无界的事件时间 Row-count over window
.window(Over.partitionBy("a").orderBy("rowtime").preceding(UNBOUNDED_ROW).as("w"))
//无界的处理时间 Row-count over window
.window(Over.partitionBy("a").orderBy("proctime").preceding(UNBOUNDED_ROW).as("w"))

有界Over Windows

  • 有界的 over window是用间隔的大小指定的
// 有界的事件时间 over window
.window(Over.partitionBy("a").orderBy("rowtime").preceding("1.minutes").as("w"))
// 有界的处理时间 over window
.window(Over.partitionBy("a").orderBy("proctime").preceding("1.minutes").as("w"))
// 有界的事件时间 Row-count over window
.window(Over.partitionBy("a").orderBy("rowtime").preceding("10.rows").as("w"))
// 有界的处理时间 Row-count over window
.window(Over.partitionBy("a").orderBy("procime").preceding("10.rows").as("w"))

实际案例

    val resultTable = sensorTable
      .window(Over partitionBy 'id orderBy 'ts preceding 2.rows as 'ow)
      .select('id, 'ts, 'id.count over 'ow, 'temperature.avg over 'ow)

跳转顶部


SQL中的Group Windows

Group Windows定义在 SQL 查询的 Group By子句中

  • TUMBLE(time_attr, interval)

    • 定义一个滚动窗口,第一个参数是时间字段,第二个参数是窗口长度
  • HOP(time_attr, interval, interval)

    • 定义一个滑动窗口,第一个参数是时间字段,第二个参数是窗口滑动步长,第三个是 窗口长度
  • SESSION(time_attr, interval)

    • 定义一个会话窗口,第一个参数是时间字段,第二个参数是窗口间隔

实现案例

    tableEnv.createTemporaryView("sensor", sensorTable)
    val resultSqlTable = tableEnv.sqlQuery(
      """
        |select
        |id,
        |count(id),
        |avg(temperature),
        |tumble_end (ts, interval '10' second)
        |from sensor
        |group by
        |id , tumble(ts, interval '10' second)
        |""".stripMargin
    )

跳转顶部


SQL中的Over Windows

Over做窗口聚合时,所有聚合必须在同一窗口上定义,也就是说必须是相同的分区、排序和范围

目前仅支持在当前行范围之前的窗口

ORDER BY必须在单一的时间属性上指定

SELECT COUNT(amount) OVER (
	PARTITION BY user
	ORDER BY proctime
	ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
FROM Orders

实际案例

    val resultSqlTable = tableEnv.sqlQuery(
      """
        |select id, ts ,count(id) over ow ,avg(temperature) over ow
        |from sensor
        |window ow as (
        | partition by id
        | order by ts
        | rows between 2 preceding and current row
        |)
        |""".stripMargin
    )

跳转顶部


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值