【Flink】Flink 中的时间和窗口之窗口其他API的使用

1. 窗口的其他API简介

对于一个窗口算子而言,窗口分配器和窗口函数是必不可少的。除此之外,Flink 还提供了其他一些可选的 API,可以更加灵活地控制窗口行为。

1.1 触发器(Trigger)

触发器主要是用来控制窗口什么时候触发计算。所谓的"触发计算"本质上就是执行窗口函数,所以可以认为是计算得到结果并输出的过程。

基于WindowsStream调用.trigger()方法,参数传入一个自定义的窗口触发器(Trigger)。

stream.keyBy(...).window(...).trigger(new MyTrigger())

Trigger 是窗口算子的内部属性,每个窗口分配器(WindowAssigner)都会对应一个默认的触发器;对于 Flink 内置的窗口类型,它们的触发器都已经做了实现。例如,所有事件时间窗口,默认的触发器都是 EventTimeTrigger;类似还有 ProcessingTimeTriggerCountTrigger。所以一般情况下是不需要自定义触发器的。

Trigger是一个抽象类,自定义时必须实现以下四个抽象方法:

  • onElement():窗口中每到来一个元素,都会调用这个方法。
  • onEventTime():当注册的事件时间定时触发时,将调用这个方法。
  • onProcessingTime ():当注册的处理时间定时器触发时,将调用这个方法。
  • clear():当窗口关闭销毁时,调用这个方法。一般用来清除自定义的状态。

除了 clear()比较像生命周期方法,其他三个方法其实都是对某种事件的响应。onElement()是对流中数据元素到来的响应;而另两个则是对时间的响应。这些方法参数中都有一个“触发器上下文”(TriggerContext)对象,可以用来注册定时器回调(callback)。对于时间窗口(TimeWindow)而言,就是在窗口的结束时间设定了一个定时器,这样到时间就可以触发窗口的计算输出了。

另外这三个方法的返回类型都是 TriggerResult,这是一个枚举类型(enum),其中定义了对窗口进行操作的四种类型

  • CONTINUE(继续):什么都不做
  • FIRE(触发):触发计算,输出结果
  • PURGE(清除):清空窗口中的所有数据,销毁窗口
  • FIRE_AND_PURGE(触发并清除):触发计算输出结果,并清除窗口

Trigger 除了可以控制触发计算,还可以定义窗口什么时候关闭(销毁)。并且TriggerResult的返回结果可以让计算输出结果和关闭窗口分开执行。

示例:
在日常业务场景中,我们经常会开比较大的窗口来计算每个窗口的pv 或者 uv 等数据。但窗口开的太大,会使我们看到计算结果的时间间隔变长。所以我们可以使用触发器,来隔一段时间触发一次窗口计算。我们在代码中计算了每个 url 在 10 秒滚动窗口的 pv 指标,然后设置了触发器,每隔 1 秒钟触发一次窗口的计算。

public static void main(String[] args) throws Exception {StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);// 创建自定义数据源的实时流DataStream<Event> stringDataStreamSource = env.addSource(new CustomSource()).assignTimestampsAndWatermarks(WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO).withTimestampAssigner(new SerializableTimestampAssigner<Event>() {@Overridepublic long extractTimestamp(Event element, long recordTimestamp) {return element.getTimestamp();}}));stringDataStreamSource.keyBy(Event::getUrl).window(TumblingEventTimeWindows.of(Time.seconds(10))).trigger(new MyTrigger()).process(new WindowResult()).print();stringDataStreamSource.print("data");env.execute();}public static class WindowResult extends ProcessWindowFunction<Event, UrlViewCount, String, TimeWindow> {@Overridepublic void process(String s, ProcessWindowFunction<Event, UrlViewCount, String, TimeWindow>.Context context, Iterable<Event> elements, Collector<UrlViewCount> out) throws Exception {out.collect(new UrlViewCount(s, elements.spliterator().getExactSizeIfKnown(), context.window().getStart(), context.window().getEnd()));}}private static class UrlViewCount {private String s;private long size;private long start;private long end;public UrlViewCount(String s, long size, long start, long end) {this.s = s;this.size = size;this.start = start;this.end = end;}@Overridepublic String toString() {return "UrlViewCount{" +"s='" + s + '\'' +", size=" + size +", start='" + start + '\'' +", end='" + end + '\'' +'}';}}public static class MyTrigger extends Trigger<Event, TimeWindow> {@Overridepublic TriggerResult onElement(Event element, long timestamp, TimeWindow window, TriggerContext ctx) throws Exception {ValueState<Boolean> isFirstEvent = ctx.getPartitionedState(new ValueStateDescriptor<Boolean>("first-event", Types.BOOLEAN));if (isFirstEvent.value() == null) {for (long i = window.getStart(); i < window.getEnd() ; i = i + 1000L) {ctx.registerEventTimeTimer(i);}isFirstEvent.update(true);}return TriggerResult.CONTINUE;}@Overridepublic TriggerResult onProcessingTime(long time, TimeWindow window, TriggerContext ctx) throws Exception {return TriggerResult.CONTINUE;}@Overridepublic TriggerResult onEventTime(long time, TimeWindow window, TriggerContext ctx) throws Exception {return TriggerResult.FIRE;}@Overridepublic void clear(TimeWindow window, TriggerContext ctx) throws Exception {ValueState<Boolean> isFirstEvent = ctx.getPartitionedState(new ValueStateDescriptor<Boolean>("first-event", Types.BOOLEAN));isFirstEvent.clear();}}

输出结果:
在这里插入图片描述

1.2 移除器(Evictor)

移除器主要用来定义移除某些数据的逻辑。基于 WindowedStream 调用.evictor()方法,就可以传入一个自定义的移除器(Evictor)Evictor 是一个接口,不同的窗口类型都有各自预实现的移除器。

Evictor 接口定义了两个方法:

  • evictBefore():定义执行窗口函数之前的移除数据操作
  • evictAfter():定义执行窗口函数之后的以处数据操作

默认情况下,预实现的移除器都是在执行窗口函数(window fucntions)之前移除数据的。

1.3 允许延迟(Allowed Lateness)

在事件时间语义下,窗口会出现迟到的数据。之所以出现迟到数据是因为在乱序流中,水位线并一定能保证时间戳更早的所有数据不会再出现,当水位线已经到达窗口的结束时间时,窗口触发计算并输出结果,这时一般就要销毁窗口了;如果还有本该属于这个窗口的数据到达,默认情况下会被丢弃。

大多数情况下直接丢弃数据会导致统计结果不准,为了解决迟到数据的问题,Flink提供了一个特殊接口,可以为窗口算子设置一个"允许最大延迟"(Allowed Lateness)。也就是说,我们可以设定允许延迟一段时间,在这段时间内,窗口不会销毁,继续到来的数据依然可以进入窗口中并触发计算。直到水位线推进到了 窗口结束时间 + 延迟时间,才真正将窗口的内容清空,正式关闭窗口。

基于 WindowedStream 调用.allowedLateness()方法,传入一个Time类型的延迟时间,就可以表示允许这段时间内的延迟数据。

stream.keyBy(...).window(TumblingEventTimeWindows.of(Time.hours(1))).allowedLateness(Time.minutes(1))

比如上面的代码中,我们定义了 1 小时的滚动窗口,并设置了允许 1 分钟的延迟数据。也就是说,在不考虑水位线延迟的情况下,对于 8 点~9 点的窗口,本来应该是水位线到达 9 点整触发计算并关闭窗口;现在允许延迟 1 分钟,那么 9 点整就只是触发一次计算并输出结果,并不会关窗。后续到达的数据,只要属于 8 点~9 点窗口,依然可以在之前统计的基础上继续叠加,并且再次输出一个更新后的结果。直到水位线到达了 9 点零 1 分,这时就真正清空状态、关闭窗口,之后再来的迟到数据就会被丢弃了。

从这里可以看到,窗口的触发计算(Fire)清除(Purge)操作确实可以分开。不过在默认情况下,允许的延迟是 0,这样一旦水位线到达了窗口结束时间就会触发计算并清除窗口,两个操作看起来就是同时发生了。当窗口被清除(关闭)之后,再来的数据就会被丢弃。

1.4 将迟到的数据放入侧输出流

对于处理迟到数据,仅仅提供延迟时间还是会出现迟到的数据,所以Flink提供了另外一种方式处理迟到数据。可以将迟到数据放到侧输出流(side output)进行另外的处理。所谓的侧输出流,相当于是数据流的一个“分支”,这个流中单独放置那些错过了该上的车、本该被丢弃的数据。

基于 WindowedStream 调用.sideOutputLateData() 方法,就可以实现这个功能。方法需要传入一个“输出标签”(OutputTag),用来标记分支的迟到数据流。因为保存的就是流中的原始数据,所以OutputTag的类型与流中数据类型相同。

DataStream<Event> stream = env.addSource(...);
OutputTag<Event> outputTag = new OutputTag<Event>("late") {};
stream.keyBy(...).window(TumblingEventTimeWindows.of(Time.hours(1)))
.sideOutputLateData(outputTag)

将迟到数据放入侧输出流之后,还可以将它提取出来。基于窗口处理完成之后的DataStream,调用.getSideOutput()方法,传入对应的输出标签,就可以获取到迟到数据所在的流了。

SingleOutputStreamOperator<AggResult> winAggStream = stream.keyBy(...).window(TumblingEventTimeWindows.of(Time.hours(1)))
.sideOutputLateData(outputTag)
.aggregate(new MyAggregateFunction())
DataStream<Event> lateStream = winAggStream.getSideOutput(outputTag);

这里注意,getSideOutput()SingleOutputStreamOperator的方法,获取到的侧输出流数据
类型应该和 OutputTag 指定的类型一致,与窗口聚合之后流中的数据类型可以不同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/756254.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大模型系列】统一图文理解与生成(BLIP/BLIPv2/InstructBLIP)

文章目录 1 BLIP(2022, Salesforce Research)1.1 简介1.2 数据角度1.3 模型角度1.4 BLIP预训练的目标 2 BLIP2(ICML2023, Salesforce)2.1 简介2.2 模型架构2.3 训练细节 3 InstructBLIP(2023, Salesforce)3.1 指令微调技术(Instruction-tuning)3.2 数据集准备3.3 Instruction-a…

docker入门(二)—— docker三大概念(镜像、容器、仓库)

docker 的三大必要概念 docker 的三大必要概念——镜像、容器、仓库 docker 架构图 镜像&#xff08;image&#xff09;&#xff1a;模版。&#xff08;web项目&#xff1a;1、环境 2、配置变量 3、上线项目 4、配置项目需要的静态文件&#xff09;打包成镜像 docker 镜像&a…

代码随想录阅读笔记-哈希表【两个数组的交集】

题目 给定两个数组&#xff0c;编写一个函数来计算它们的交集。 说明&#xff1a; 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。 提示&#xff1a; 1 < nums1.length, nums2.length < 10000 < nums1[i], nums2[i] < 1000 思路 交集&…

【源码阅读】EVMⅢ

参考[link](https://blog.csdn.net/weixin_43563956/article/details/127725385 大致流程如下&#xff1a; 编写合约 > 生成abi > 解析abi得出指令集 > 指令通过opcode来映射成操作码集 > 生成一个operation 以太坊虚拟机的工作流程&#xff1a; 由solidity语言编…

鸿蒙实战开发:【FaultLoggerd组件】讲解

简介 Faultloggerd部件是OpenHarmony中C/C运行时崩溃临时日志的生成及管理模块。面向基于 Rust 开发的部件&#xff0c;Faultloggerd 提供了Rust Panic故障日志生成能力。系统开发者可以在预设的路径下找到故障日志&#xff0c;定位相关问题。 架构 Native InnerKits 接口 Si…

Linux操作系统——多线程

1.线程特性 1.1线程优点 创建一个新线程的代价要比创建一个新进程小得多与进程之间的切换相比&#xff0c;线程之间的切换需要操作系统做的工作要少很多线程占用的资源要比进程少很多能充分利用多处理器的可并行数量在等待慢速I/O操作结束的同时&#xff0c;程序可执行其他的计…

《1w实盘and大盘基金预测 day7》

昨日预测有点差劲&#xff0c;最低点也相差五个点。 打分C 公众号&#xff1a;JavaHelmet 昨天预测&#xff1a; 3052-3062-3076-3115 3067是趋势线&#xff0c;有回踩需求 5-30-60分钟级别顶钝 大盘冲到标红的点位3115或者3100就需注意。不要随意追高&#xff08;最高309…

备战蓝桥杯---牛客寒假训练营2VP

题挺好的&#xff0c;收获了许多 1.暴力枚举&#xff08;许多巧妙地处理细节方法&#xff09; n是1--9,于是我们可以直接暴力&#xff0c;对于1注意特判开头0但N&#xff01;1&#xff0c;对于情报4&#xff0c;我们可以把a,b,c,d的所有取值枚举一遍&#xff0c;那么如何判断有…

ModbusTCP转Profinet网关高低字节交换切换

背景&#xff1a;在现场设备与设备通迅之间通常涉及到从一种字节序&#xff08;大端或小端&#xff09;转换到另一种字节序。大端字节序是指高位字节存储在高地址处&#xff0c;而小端字节序是指低位字节存储在低地址处。在不动原有程序而又不想或不能添加程序下可选用ModbusTC…

OCP NVME SSD规范解读-13.Self-test自检要求

4.10节Device Self-test Requirements详细描述了数据中心NVMe SSD自检的要求&#xff0c;这一部分规范了设备自身进行各种健康检查和故障检测的过程。自检对于确保SSD的正常运行和提前预防潜在故障至关重要。 在进行设备自检时&#xff0c;设备应当确保不对用户数据造成破坏&am…

【人工智能】Gitee AI 天数智芯有奖体验开源AI模型,一定能有所收货,快来体验吧

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读小5的系列文章。 这是《人工智能》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 目录 前言两大赛道天数智芯1.模型地址2.天数智芯专区3.选择模型4.模型详情页5.部署模型6.成功部署7.执行例子8.移除模型 千模盲…

03python注释与输入函数

Python 注释的作用: 注释可用于解释 Python 代码。 注释可用于提高代码的可读性。 在测试代码时,可以使用注释来阻止执行。 注释可以放在一行的末尾,Python 将忽略该行的其余部分: 实例1 print("Hello, World!") #打印输出Hello,World print(9-3) #输出9…

【mybatis】objectwrapper解读

简介 在 MyBatis 中&#xff0c;ObjectWrapper 是一个关键的接口&#xff0c;用于详细封装了对象的属性信息。ObjectWrapper 主要用于内部操作&#xff0c;它抽象了对象的属性操作&#xff0c;使得 MyBatis 能够统一处理原生类型、Bean 对象以及 Map 集合等。 类图展示 主要功…

Vue组件封装方案对比——v-if方式与内置component方式

近期在准备搭建一个通用组件库&#xff0c;而公司现有的各个系统也已有自己的组件库只是没抽离出来&#xff0c;但是目前有两套不同的组件封装方案&#xff0c;所以对于方案的选择比较困惑&#xff0c;于是对两种方式进行了对比&#xff0c;结合网上找到的一些开源组件库进行分…

抖音店铺规划运营管理计划数据分析工作表

【干货资料持续更新&#xff0c;以防走丢】 抖音店铺规划运营管理计划数据分析表 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 抖音小店运营规划工作表格&#xff08;完整资料包含以下内容&#xff09; 目录 1. 抖店运营管理决策表&#xff1a;该表格用于记…

三维指静脉生物识别成像设备设计和多视图验证研究

文章目录 三维指静脉生物识别成像设备设计和多视图验证研究总结摘要介绍多视角指静脉识别模型结构内容特征编码Transformer(CFET)主导特征选择模块(DFSM) 实验和结果数据集实施细节视角研究池化层的作用消融实验和SOTA方法比较 论文: Study of 3D Finger Vein Biometrics on I…

Linux——进程通信(三)命名管道

前言 我们在之前学习了匿名管道与匿名管道的应用——进程池&#xff0c;但是匿名管道的通信&#xff0c;需要有血缘关系的进程&#xff08;通过fork创建的进程们&#xff09;&#xff0c;如果我想让两个毫不相干的进程进行通信&#xff0c;可以采样命名管道的方式&#xff08;…

Go语言中的锁与管道的运用

目录 1.前言 2.锁解决方案 3.管道解决方案 4.总结 1.前言 在写H5小游戏的时候&#xff0c;由于需要对多个WebSocket连接进行增、删、查的管理和对已经建立连接的WebSocket通过服务端进行游戏数据交换的需求。于是定义了一个全局的map集合进行连接的管理&#xff0c;让所有…

80后深圳设计师原创设计 妙解中小学生午休难题

3月17日至21日&#xff0c;深圳国际智能家居博览会在宝安国际会展中心举办。智慧校园展区成为焦点&#xff0c;吸引了众多目光。智荟康科技展出的午休课桌椅产品&#xff0c;为解决中小学生“趴睡”问题而研发&#xff0c;创新实用&#xff0c;在智慧校园展区中备受好评。 &…

Leetcode 79. 单词搜索

心路历程&#xff1a; 做完这道题才发现是回溯&#xff0c;一开始想的是递归&#xff0c;判断完第i个字符后&#xff0c;只需要挨个判断第i1个字符在不在第i个字符的邻域。后来发现由于不能重复使用元素&#xff0c;所以需要维护一个visited列表&#xff0c;并且在遍历所有可能…