Process Function API(底层)
Process Function API(底层)
我们之前学习的转换算子是无法访问事件的时间戳信息和水位线信息的。而这 在一些应用场景下,极为重要。例如MapFunction
这样的map
转换算子就无法访问 时间戳或者当前事件的事件时间。
基于此,DataStream API
提供了一系列的Low-Level
转换算子。可以访问时间戳、watermark
以及注册定时事件。还可以输出特定的一些事件,例如超时事件等。 Process Function
用来构建事件驱动的应用以及实现自定义的业务逻辑(使用之前的 window
函数和转换算子无法实现)。例如,Flink SQL
就是使用 Process Function
实现的。
ProcessFunction
可以看作是最底层的API
Flink
提供了 8 个 Process Function
:
-
ProcessFunction
-
KeyedProcessFunction
-
CoProcessFunction
-
ProcessJoinFunction
-
BroadcastProcessFunction
-
KeyedBroadcastProcessFunction
-
ProcessWindowFunction
-
ProcessAllWindowFunction
Keyed Process Function
这里我们重点介绍 KeyedProcessFunction
。
KeyedProcessFunction
用来操作 KeyedStream
。KeyedProcessFunction
会处理流 的每一个元素,输出为 0 个、1 个或者多个元素。所有的 Process Function
都继承自RichFunction
接口,所以都有 open()
、close()
和 getRuntimeContext()
等方法。而 KeyedProcessFunction[KEY, IN, OUT]
还额外提供了两个方法:
-
processElement(v: IN, ctx: Context, out: Collector[OUT])
, 流中的每一个元素 都会调用这个方法,调用结果将会放在Collector
数据类型中输出。Context
可以访问元素的时间戳,元素的key
,以及TimerService
时间服务。Context
还可以将结果输出到别的流(side outputs
)。 -
onTimer(timestamp: Long, ctx: OnTimerContext, out: Collector[OUT])
是一个回 调函数。当之前注册的定时器触发时调用。参数timestamp
为定时器所设定 的触发的时间戳。Collector
为输出结果的集合。OnTimerContext
和processElement
的Context
参数一样,提供了上下文的一些信息,例如定时器 触发的时间信息(事件时间或者处理时间)。
自定义一个KeyedProcessFunction
/**
* 三个参数是:key的数据类型
* 输入的数据类型
* 输出的数据类型
*/
class MyKeyedProcessFunction extends KeyedProcessFunction[String, SensorReading, String] {
var myState: ValueState[Int] = _
override def open(parameters: Configuration): Unit = {
myState = getRuntimeContext.getState(new ValueStateDescriptor[Int]("valueState", classOf[Int]))
}
override def processElement(i: SensorReading, context: KeyedProcessFunction[String, SensorReading, String]#Context,
collector: Collector[String]): Unit = {
//获取当前的key,其实还可以直接从数据里面获取
context.getCurrentKey
//获取当前数据的时间戳
context.timestamp()
//获取当前的watermark
context.timerService().currentWatermark()
/**
* 定义一个一分钟后触发的定时器,当定时器触发后,会执行onTimer方法
* 可以注册多个定时器,定时器的区别就是时间戳
* 不同的定时器执行时都是在onTimer方法里面
*/
context.timerService().registerEventTimeTimer(context.timestamp() + 60 * 1000l)
/**
* 定时器的删除,删除也是传入一个参数,参数就是时间戳
*/
// context.timerService().deleteEventTimeTimer()
}
/**
*
* @param timestamp是定时器触发的时间 ,我们可以将根据不同的时间戳来判断不同的定时器,然后执行不一样的方法
* @param ctx
* @param out
*/