处理函数介绍
处理函数(PocessFunction)是Flink提供的一个低价
的流处理Operator,允许返回所有流程序(无回环的
)的基础构建模块:
- events(流元素): ProcessFunction 可以被认为是一个可以处理Keyed Sate和定时器的FlatMapFunction。它通过调用输入流中接收到的每个事件来处理事件
- state(仅在keyed stream中使用):ProcessFunction 允许访问Flink的Keyed State,可以通过RuntimeContext访问,这与其他有状态函数访问Keyed State的方式类似
- timers(定时器,event time和processing time,仅在 keyed stream中):定时器允许应用程序对
processing time
和event time
的变化做出反应,每次对processElement(...)
的调用都会得到一个Context
对象,该对象允许访问元素事件事件的时间戳和TimeServer
。TimeServer
可以用来对尚未发生的event-time或者processing- time 注册回调,当定时器的时间到达时,onTimer(…)方法会被调用,在这个调用期间,所有的状态都会限定到创建定时器就的键,并允许定时器操纵Keyed States。
低阶 Join
为了实现对两个输入流的低阶操作,应用程序可以使用CoProcessFunction
或KeyedCoprocessFunction
。这个函数被绑定到两个不同的输入,并获得对来自两个不同输入的记录的processElement1(…)和processElement2(…)单独调用。
实现低阶Join通常遵循以下模式:
- 为了一个输入(或者两个输入)创建状态对象
- 在从其输入接收元素时更新状态
- 在接收到来自其他输入的元素时,探测状态并产生Join的结构
处理函数分类
Flink中提供了7个Process Function,他们分别是继承Abstract Rich Function(抽象富函数),分别如下:
- ProcessFuntion:流处理函数,对数据流中的每一个元素数据进行处理,processElement()方法用于处理输入流中的每一个元素并输出一个或者多个元素。支持定时器和状态处理
- KeydeProcessFunction:流处理键函数 和 ProcessFunction类似,只是它的输入流要求是KeyedStream。
- CoProcessFunction: 处理两个流的元素并产生一个输出流,为输入流中的每个元素调用,并可以产生零个或多个输出元素。CoFlatMapFunction相反,这个函数还可以通过提供CoProcessFunction.Context查询时间(事件和处理)和设置计时器。
- ProcessJoinFunction:处理两个Join流中的元素并产生一个输出
- BroadcastProcessFunction: 应用BroadcastConnectedStream的函数,该函数连接BroadcastStream,即具有广播状态的流和一个non-keyedDataStream
- KeyedBroadcastProcessFunction:应用于BrodcastConnectedStream的函数,它连接BroadcastStream,即一个具有广播状态的流和一个KeyedStream
- ProcessWindowFunction:用在基于Keyed(分组)窗口上使用处理额外信息
代码
这段代码是实现相同的累加
数据源是
li 4
wang 2
li 2
实现分组将第二个字段数字累加
package 复习
import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor}
import org.apache.flink.api.scala._
import org.apache.flink.streaming.api.functions.ProcessFunction
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.util.Collector
object ProcssFunction {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
val ds: DataStream[(String, String)] = env.socketTextStream("localhost", 6666)
.map(x => {
val fileds: Array[String] = x.split(" ")
(fileds(0), fileds(1))
})
ds.print()
ds.keyBy(0)
.process(new CountWithProcessFuntion)
.print("proc")
env.execute("test02")
}
}
/**
* 状态中的数据存储
* @param key
* @param count
*/
case class CountWithTimestamp(key:String,count:Long)
/**
* 自定义处理函数
*/
class CountWithProcessFuntion extends ProcessFunction[(String,String),(String,Long)]{
// 定义process function 中的状态
lazy val state:
ValueState[CountWithTimestamp] = getRuntimeContext.getState(new ValueStateDescriptor[CountWithTimestamp](
"myState",
classOf[CountWithTimestamp]
))
/**
* 对输入的每行数据做处理
*
* @param i
* @param context
* @param collector
*/
override def processElement(i: (String, String), context: ProcessFunction[(String, String), (String, Long)]#Context, collector: Collector[(String, Long)]): Unit = {
val current:CountWithTimestamp = state.value() match {
case null => CountWithTimestamp(i._1,1) // 初始化
case CountWithTimestamp(key,count) => CountWithTimestamp(key,count+i._2.toLong)
}
// 更新状态
state.update(current)
// 输出
collector.collect(state.value().key,state.value().count)
}
// 定时器操作 --- 可以对输入数据做处理,也可以输出数据,可以注册定时器和销毁定时器
override def onTimer(timestamp: Long, ctx: ProcessFunction[(String, String), (String, Long)]#OnTimerContext, out: Collector[(String, Long)]): Unit = super.onTimer(timestamp, ctx, out)
}