处理函数

无论是基本的转换、聚合,还是更为复杂的窗口操作,其实都是基于 DataStream 进行转换的;所以可以统称为 DataStream API,这也是 Flink 编程的核心

在更底层,我们可以不定义任何具体的算子(比如 map,filter,或者 window),而只是提炼出一个统一的 “处理”(process)操作

它是所有转换算子的一个概括性的表达,可以自定义处理逻辑,所以这一层接口就被叫作 “处理函数”(process function)

在处理函数中,我们直面的就是数据流中最基本的元素:数据事件(event)、状态(state)以及时间(time)

可以说,处理函数是我们进行 Flink 编程的“大招”,轻易不用,一旦放出来必然会扫平一切

stream.process(new MyProcessFunction())

处理函数的分类

对于不同类型的流,其实都可以直接调用.process()方法进行自定义处理,这时传入的参数就都叫作处理函数

当然,它们尽管本质相同,都是可以访问 状态和时间信息的底层 API,可彼此之间也会有所差异

1)ProcessFunction

抽象类 ProcessFunction 继承了 AbstractRichFunction,有两个泛型类型参数:I 表示 Input,也就是输入的数据类型;O 表示 Output,也就是处理完成之后输出 的数据类型

内部单独定义了两个方法:一个是必须要实现的抽象方法.processElement();另一个是非抽象方法.onTimer()

  1. .processElement()

    用于“处理元素”,定义了处理的核心逻辑,它有三个参数具体如下:

    • 输入元素:正在处理的数据,类型与流中数据类型一致

    • 当前运行的上下文:可以获取到当前的时间戳,并提供了用于查询时间和注册定时器的“定时服务”,以及将数据发送到“侧输出流”的方法.output(),定义如下

      public abstract class Context {
           public abstract Long timestamp();
           public abstract TimerService timerService();
           public abstract <X> void output(OutputTag<X> outputTag, X value);
      }
      
    • 收集器:可以调用.collect()收集数据,可以多次调用,也可以不调用

  2. .onTimer()

    这个方法是用于定时触发的操作,只有在.processElement()中注册好的定时器触发的时候才会调用

    本质上是一个基于时间的“回调”方法,通过时间的进展来触发;在事件时间语义下就是由watermark来触发

    它也有三个参数:时间戳、上下文和收集器,这里的时间戳是指设定好的触发时间,事件时间语义下即watermark


处理函数都是基于事件触发的,水位线就如同插入流中的一条数据一样; 只不过处理真正的数据事件调用的是.processElement()方法,而处理水位线事件调用的是.onTimer()

需要注意的是:在 Flink 中,只有“按键分区流” KeyedStream才支持设置定时器的操作

所以一般情况下,我们都是先做了 keyBy 分区之后,再去定义处理操作;

代码中其实更加 常见的处理函数是 KeyedProcessFunction,最基本的 ProcessFunction 反而出镜率没那么高


2)KeyedProcessFunction

我们只要基于 keyBy 之后的 KeyedStream,直接调用.process()方法,这时需要传入的参数就是 KeyedProcessFunction 的实现类

KeyedProcessFunction 的一个特色,就是可以灵活地使用定时器

注册定时器的功能,是通过上下文中提供的“定时服务”(TimerService)来实现的,具体可由上下文对象提供的.timerService()方法获取

TimerService 是 Flink 关于时间和定时器的基础服务接口,包含以下六个方法

// 获取当前的处理时间
long currentProcessingTime();
// 获取当前的水位线(事件时间)
long currentWatermark();
// 注册处理时间定时器,当处理时间超过 time 时触发
void registerProcessingTimeTimer(long time);
// 注册事件时间定时器,当水位线超过 time 时触发
void registerEventTimeTimer(long time);
// 删除触发时间为 time 的处理时间定时器
void deleteProcessingTimeTimer(long time);
// 删除触发时间为 time 的处理时间定时器
void deleteEventTimeTimer(long time);

注意:未作按键分区的 DataStream 不支持定时器操作,只能获取当前时间

3)ProcessWindowFunction
4)ProcessAllWindowFunction
5)CoProcessFunction
6)ProcessJoinFunction
7)BroadcastProcessFunction
8)KeyedBroadcastProcessFunction
posted @ 2022-11-05 18:22  黄一洋  阅读(14)  评论(0)    收藏  举报