Flink 窗口聚合提前触发参数(流和SQL)

11 篇文章 1 订阅

不开启提前触发窗口

如以下 demo,从 kafka 读取数据,做 窗口聚合,输出一天的 pv、uv


-- kafka source
drop table if exists user_log;
CREATE TABLE user_log
(
    user_id     VARCHAR,
    item_id     VARCHAR,
    category_id VARCHAR,
    behavior    VARCHAR,
    proc_time  as PROCTIME(),
    ts          TIMESTAMP(3),
    WATERMARK FOR ts AS ts - INTERVAL '5' SECOND
) WITH (
      'connector' = 'kafka'
      ,'topic' = 'user_log'
      ,'properties.bootstrap.servers' = 'localhost:9092'
      ,'properties.group.id' = 'user_log'
      ,'scan.startup.mode' = 'latest-offset'
      ,'format' = 'json'
      );

drop table if exists user_log_sink_1;
CREATE TABLE user_log_sink_1
(
    wCurrent string
    ,wStart     STRING
    ,wEnd    STRING
    ,pv    bigint
    ,uv    bigint
    ,primary key(wCurrent,wStart,wEnd) not enforced
) WITH (
--       'connector' = 'print'
      'connector' = 'upsert-kafka'
      ,'topic' = 'user_log_sink'
      ,'properties.bootstrap.servers' = 'localhost:9092'
      ,'properties.group.id' = 'user_log'
      ,'key.format' = 'json'
      ,'value.format' = 'json'
      );

-- window aggregation
insert into user_log_sink_1
select date_format(now(), 'yyyy-MM-dd HH:mm:ss')
     ,date_format(TUMBLE_START(proc_time, INTERVAL '1' minute), 'yyyy-MM-dd HH:mm:ss') AS wStart
     ,date_format(TUMBLE_END(proc_time, INTERVAL '1' minute), 'yyyy-MM-dd HH:mm:ss') AS wEnd
     ,count(1) coun
     ,count(distinct user_id)
from user_log
group by TUMBLE(proc_time, INTERVAL '1' minute)

  • 注: 为了方便测试,1 天的窗口改为 1 分钟的窗口

任务流图如下:

任务输出如下:


+I[2022-06-01 17:14:00, 2022-06-01 17:13:00, 2022-06-01 17:14:00, 29449, 9999]
+I[2022-06-01 17:15:00, 2022-06-01 17:14:00, 2022-06-01 17:15:00, 29787, 9999]
+I[2022-06-01 17:16:00, 2022-06-01 17:15:00, 2022-06-01 17:16:00, 29765, 9999]
+I[2022-06-01 17:17:00, 2022-06-01 17:16:00, 2022-06-01 17:17:00, 29148, 9999]
+I[2022-06-01 17:18:00, 2022-06-01 17:17:00, 2022-06-01 17:18:00, 30079, 9999]

可以明显的看到,1分钟的窗口,每分钟输出了一次结果,这就比较尴尬了,因为 1 天的窗口,也只会在窗口结束的时候,触发一次计算

对于实时的任务,每天结束的时候,才输出计算的结果,没有任何意义,我们需要的是实时更新的结果

我们需要的是像 Streaming api 一样的窗口,有触发器可以提前触发计算,输出计算的中间结果,如下:


.windowAll(TumblingEventTimeWindows.of(Time.days(1)))
.trigger(ContinuousEventTimeTrigger.of(Time.seconds(5))

提前触发窗口 

设置参数:


val tabEnv = StreamTableEnvironment.create(env, settings)
val tabConf = tabEnv.getConfig
tabConf.set("table.exec.emit.early-fire.enabled", "true")
tabConf.set("table.exec.emit.early-fire.delay", "5000")

可以提前触发窗口的结果,任务输出结果如下:


2022-06-01 17:54:21,031 INFO  - add parameter to table config: table.exec.emit.early-fire.enabled = true
2022-06-01 17:54:21,032 INFO  - add parameter to table config: table.exec.emit.early-fire.delay = 5000
2022-06-01 17:54:21,032 INFO  - add parameter to table config: pipeline.name = test_table_parameter

+I[2022-06-01 17:54:35, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 2527, 2500]
-U[2022-06-01 17:54:40, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 2527, 2500]
+U[2022-06-01 17:54:40, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 5027, 5000]
-U[2022-06-01 17:54:45, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 5027, 5000]
+U[2022-06-01 17:54:45, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 7527, 7500]
-U[2022-06-01 17:54:50, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 7527, 7500]
+U[2022-06-01 17:54:50, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 10079, 9999]
-U[2022-06-01 17:54:55, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 10079, 9999]
+U[2022-06-01 17:54:55, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 12579, 9999]
-U[2022-06-01 17:55:00, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 12579, 9999]
+U[2022-06-01 17:55:00, 2022-06-01 17:54:00, 2022-06-01 17:55:00, 14579, 9999]

+I[2022-06-01 17:55:05, 2022-06-01 17:55:00, 2022-06-01 17:56:00, 2500, 2500]
-U[2022-06-01 17:55:10, 2022-06-01 17:55:00, 2022-06-01 17:56:00, 2500, 2500]
+U[2022-06-01 17:55:10, 2022-06-01 17:55:00, 2022-06-01 17:56:00, 5299, 5000]
。。。忽略部分中间结果
-U[2022-06-01 17:55:55, 2022-06-01 17:55:00, 2022-06-01 17:56:00, 25364, 9999]
+U[2022-06-01 17:55:55, 2022-06-01 17:55:00, 2022-06-01 17:56:00, 27864, 9999]
-U[2022-06-01 17:56:00, 2022-06-01 17:55:00, 2022-06-01 17:56:00, 27864, 9999]
+U[2022-06-01 17:56:00, 2022-06-01 17:55:00, 2022-06-01 17:56:00, 29867, 9999]

+I[2022-06-01 17:56:05, 2022-06-01 17:56:00, 2022-06-01 17:57:00, 2500, 2500]
-U[2022-06-01 17:56:10, 2022-06-01 17:56:00, 2022-06-01 17:57:00, 2500, 2500]

可以看到,每 5 秒触发了一次计算,除了第一次只有一条 insert 消息,后续的每次触发都有一条 -U/+U 的消息,累加了窗口的结果

总结

Flink sql 的窗口聚合也可以想 Streaming api 设置 trigger 一样,提前触发计算,并且输出的结果是 upsert 流,会发出 -U/+U 两条数据(输出到 upsert-kafka 就只有 +U 的消息了)

其他

      除以上两种方式外,另一种办法是开一分钟窗口(根据自己输出频率来设定窗口)做初步聚合,然后根据日期做二次聚合

        两种方式有一个区别,提前输出方式,因为窗口没有关闭,输出的数据是update,而二次聚合方式,因为窗口已经关闭,所以每分钟都会insert一条数据,当需要数据绘制曲线图时,推荐二次聚合方式,如果只是显示一个计算数字,则推荐使用提前输出方式。

统计一天每10分钟累计独立用户数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flink SQL 中的窗口是将无限数据划分为有限大小的块,以便进行有限的处理和聚合窗口可以按照时间或数据数量进行定义。Flink SQL 支持以下类型的窗口: 1. 滚动窗口(Tumbling Window):滚动窗口是一系列固定大小的、不重叠的时间段,按照固定的时间长度进行滚动,例如每 5 秒一个窗口。 2. 滑动窗口(Sliding Window):滑动窗口是一系列大小固定、可以有重叠的时间段,按照固定的时间长度进行滑动,例如每 5 秒滑动一次,窗口大小为 10 秒。 3. 会话窗口(Session Window):会话窗口是一组活动时间段的集合,这些时间段之间的间隔小于或等于指定的时间长度。会话窗口不需要固定的窗口长度,而是根据数据本身的属性动态计算。 Flink SQL 中的窗口可以通过以下语法进行定义: ```sql SELECT ... FROM ... WHERE ... GROUP BY ... WINDOW <window_type> ( <window_property> ) ``` 其中,`<window_type>` 可以是 `TUMBLING`, `SLIDING` 或 `SESSION`,`<window_property>` 取决于窗口类型,例如: - 对于滚动窗口,可以使用 `SIZE` 或 `TIME` 参数指定窗口大小或时间长度,例如 `WINDOW TUMBLING (SIZE 5 MINUTES)`。 - 对于滑动窗口,可以使用 `SIZE` 和 `SLIDE` 参数分别指定窗口大小和滑动步长,例如 `WINDOW SLIDING (SIZE 5 MINUTES, SLIDE 1 MINUTE)`。 - 对于会话窗口,可以使用 `GAP` 参数指定最大间隔时间,例如 `WINDOW SESSION (GAP 5 MINUTES)`。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值