flink 自定义 窗口_Flink--Window API,时间语义和WaterMark

Window API

流数据来了之后需要对它按照时间窗口进行划分,其中window可以看作桶。过来的数据流向一个个桶里面。

Window的两个操作构成:一个是设置窗口.window(keyby之后);一个是窗口计算函数(reduce,aggregate,apply,process)

设置窗口:

    • 时间窗口(按照时间进行划分)
    • 计数窗口(按照过来的数据数量进行划分)
    • 滚动窗口(例如:.timeWidow(Time.second(15)))

c6e6c8323396031944ee520c19452e40.png
每隔15秒划分一个窗口,窗口和窗口间不存在交叉
    • 滑动窗口(例如:.timeWindow(Time.seconds(15), Time.seconds(5)))

f9289150042d20f1baa16113b6ef0118.png
设定滑动窗口,窗口与窗口存在交叉
    • 会话窗口(指定间隔时间session gap超过某个值)

cd98be913339125641f388f14caaa751.png

窗口计算函数:

    • 增量聚合函数:ReduceFunction,AggregateFunction;流式处理过程;(对每条数据到来进行计算,保持一个中间状态。)
    • 全窗口函数:WindowFunction(.apply()方法里),ProcessWindowFunction,类似批处理。(先把窗口的数据收集起来,到点计算,等到窗口关闭则开始输出。)可以做更多操作。

其他API:

.trigger()----触发器

实践中注意:

1,遇到了统计一天用户购买量的场景,flink默认的时间是8:00AM--次日8:00AM。需要设置偏移量。

  • window( TumblingProcessingTimeWindows.of(Time.days(1), Time.hours(-8)) ) //设置偏移量。时区转换。

2,传入的数据流比较稀疏,用滑动窗口会重复输出值。(某个元素属于多个滑动窗口)

3,会话窗口可以获取用户一段实践的行为,可以将其运用在实时推荐。

时间语义及实现:

数据有两种时间语义:(我们一般更加关注EventTime

  • EventTime:数据产生时间。
  • ProcessonTime:数据处理时间。

在Flink代码设置环境的时候我们会设置时间语义:

  • env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

WaterMark

为什么我们需要WaterMark?

7f7539dda7e5e0c2fcf794404f6e30e3.png
数据存在乱序的情况

因为分布式,网络等原因导致数据产生到Flink收到数据会有乱序。如果按照eventTime来决定窗口内的数据是否运行,就不能明确数据是否全部都来了。因为我们是实时处理,也不能无限期等下去。为了处理乱序数据流,需要有一个机制来保证达到一个特定时间就触发window计算

PS:处理乱序数据,Flink有三重保证:

  • watermark可以设置延迟时间
  • window的allowedLateness方法,可以设置窗口允许处理迟到数据的时间
  • window的sideOutputLateData方法,可以将迟到的数据写入侧输出流

WaterMark如何来解决这个问题?

WaterMark核心思想(多等一下):数据流中包含时间戳,我们遇到一个时间戳达到了窗口关闭时间,不应该立刻触发窗口计算,而是等待一段时间,等迟到的数据来了再关闭窗口。

waterMark实现:waterMark实际上是一条特殊的数据记录,插入到数据流中。

Watermark = 当前Timestep最大时间戳 - 延迟时间

Watermark 用于表示 timestamp 小于 Watermark 的数据,都已经到达了。之后就不会再来时间戳比watermark里面的数值小的数据了。因此,window 的计算也是由Watermark 触发的。

4d1e1a86309081a7592fb7ca04ed58fb.png
表示WaterMark=5之前的数据已经到齐

WaterMark设置比较大的延迟,对应的准确性得到保证,但是实时性减少。具体在应用过程中根据情况来设置。

WaterMark传递

27189108014c0d5d4b48dd3123e475bf.png

在分布式系统中Task计算节点存在多个输入和多个输出的情况。对应的WaterMark分配原则有两种:

  • 多流输出(图:2,4):通过广播的形式传播下去。
  • 多流输出(图:1,3):先创建一个分区的WM,选择最小的watermark(他之前的数据都到齐了)

WaterMark代码引入

一般的有两个操作:提取时间戳字段设置延迟时间

  1. 比较稀疏的话,用断点式(AssignerWithPunctuatedWatermarks)生成WaterMark好一点,其中默认是200ms。
  2. 对于比较密集的话用周期性(AssignerWithPeriodicWatermarks)生成WaterMark,断点式比较费性能。
  • AssignerWithPeriodicWatermarks(周期性生成WM,隔一段时间生成数据,自动插入数据。

可以自定义一个waterMarkAssigner。也可以用BoundedOutOfOrdernessTimestampExtractor方法

.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor<Map<String, String>>(Time.minutes(10)) // 延迟时间

{

// 提取时间戳字段

@Override

public long extractTimestamp(Map<String, String> element) {

return Long.parseLong(element.get("ts"));

}

})

  • AssignerWithPunctuatedWatermarks(自定义一个断点式生成watermark的Assigner
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值