-
处理函数的功能和使用
之前学习的转换算子,一般只是针对某种具体操作来而言,能够拿到的信息比较有 限。比如 map 算子,只能获取到当前的数据, 定义它转换之后 的形式;而像窗口聚合这样的复杂操作, 还可以获取到当前的状态(以累加器 Accumulator 形式出现)。另外还有富函数类,比如RichMapFunction, 提供了获取运行时上下文的方法 getRuntimeContext(),可以拿到状态,还有并行度、任务名 称之类的运行时信息。但是无论那种算子, 如果我们想要访问事件的时间戳, 或者当前的水位线信息, 都是做不到的。在定义生成规则之后,水位线会源源不断地产生, 像数据一样在任务间流动,我们不能像数据一样去处理它; 跟时间相关的操作, 目前我们只会用窗口来处理。而在有些应用需求中,要求我们对时间有更精细的控制,需要能够获取水位线,甚至要“把控时间”, 这就不是基本的时间窗口能够实现的了。处理函数提供了一个“定时服务” (TimerService), 可以通过它访问流中的事件(event)、 时间戳(timestamp)、水位线 (watermark),甚至可以注册“定时事件”。而且处理函数继承了 AbstractRichFunction 抽象类, 所以拥有富函数类的所有特性, 同样可以访问状态(state) 和其他运行时信息。此外, 处理函 数还可以直接将数据输出到侧输出流(side output) 中。所以, 处理函数是最为灵活的处理方法,可以实现各种自定义的业务逻辑;同时也是整个 DataStream API 的底层基础。
处理函数的使用与基本的转换操作类似, 只需要直接基于 DataStream 调用.process()方法传入一个 ProcessFunction 作为参数就可以了。
应用示例:package com.company.flink.demo; import com.company.flink.data.ClickSource; import com.company.flink.entity.Event; import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner; import org.apache.flink.api.common.eventtime.WatermarkStrategy; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.streaming.api.functions.ProcessFunction; import org.apache.flink.util.Collector; import java.time.Duration; public class ProcessFunctionDemo { public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); env.addSource(new ClickSource()) .assignTimestampsAndWatermarks( WatermarkStrategy.<Event>forBoundedOutOfOrderness(Duration.ZERO) .withTimestampAssigner((SerializableTimestampAssigner<Event>) (event, l) -> event.timestamp) ).process(new ProcessFunction<Event, String>() { @Override public void processElement(Event value, Context ctx, Collector<String> out) { if (value.user.equals("zhangsan")) { out.collect("name = " + value.user + ", url = " + value.url); out.collect("name = " + value.user + ", url = " + value.url); } else if (value.user.equals("lisi")) { out.collect("name = " + value.user + ", url = " + value.url); } //getRuntimeContext(); //获取运行时上下文 //ctx.timerService().currentWatermark() 获取水位线 } //定时器 /*@Override public void onTimer(long timestamp, ProcessFunction<Event, String>.OnTimerContext ctx, Collector<String> out) throws Exception { super.onTimer(timestamp, ctx, out); }*/ }) .print(); env.execute(); } }1) processElement():
用于“处理元素”,定义处理的核心逻辑。这个方法对于流中的每个元素都会调用一次。2)onTimer():
用于定义定时触发的操作。这个方法只有在注册好的定时器触发的时候才会调用,定时器是通过“定时服务”TimerService 来注册的。打个 比方, 注册定时器(timer) 就是设了一个闹钟, 到了设定时间就会调用 onTimer()。所以它本质是基于时间的“回调”方法,在事件时间语义下就由水位线(watermark) 来触发了。
需要注意的是,onTimer()方法只是定时器触发时的操作,而定时器(timer) 真正的设置需要用到上下文 ctx
Flink处理函数
于 2022-09-10 18:01:49 首次发布
本文详细介绍了Flink的处理函数,包括ProcessFunction、KeyedProcessFunction等,强调其在时间戳、水位线、定时器等方面的灵活性,并提供了一个统计最近10秒内最热门URL的案例,演示了如何结合窗口和增量聚合实现Top N问题,以及在全窗口和按键分区窗口中遇到的问题和解决方案。

最低0.47元/天 解锁文章
1228

被折叠的 条评论
为什么被折叠?



