DataStream.process(processFucntion)
KeyedDataStream .process(keyedProcessFunction)
windowStream .process(processWindowFunction)
connectedStream.process(CoProcessFunction)
windowAllSteam.process(processAllWindowFunction)
processFunction都继承了RichFunction
package flinkSourse
import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor}
import org.apache.flink.configuration.Configuration
import org.apache.flink.streaming.api.TimeCharacteristic
import org.apache.flink.streaming.api.functions.KeyedProcessFunction
import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.util.Collector
object FlinkProcessFunction {
def main(args: Array[String]): Unit = {
val executionEnvironment: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
executionEnvironment.setParallelism(1)
// executionEnvironment.setStreamTimeCharacteristic(TimeCharacteristic.EventTime) //watermark周期性生成,默认是200ms
val stream2: DataStream[String] = executionEnvironment.socketTextStream("127.0.0.1", 1111)
val transforStream: DataStream[SensorReading] = stream2.map(data => {
val tmpList: Array[String] = data.split(",")
SensorReading(tmpList(0), tmpList(1).toLong * 1000, tmpList(2).toDouble)
})
//如果10s内的温度是连续上升的,输出报警信息
//如果当前温度是上升的,就加一个10s的定时器,如果10s连续上升则报警
transforStream.keyBy(_.id).process(new TemperatureIncreWarning(20000)).print("warningStream")
executionEnvironment.execute("transform")
}
}
class TemperatureIncreWarning(timeDuration: Int) extends KeyedProcessFunction[String, SensorReading, String] {
//保存一个状态进行温度数据比较,保存一个状态存储最初时间戳的状态
var lastTempraturValueState: ValueState[Double] = _
var initTimeStampValueState: ValueState[Long] = _
override def open(parameters: Configuration): Unit = {
lastTempraturValueState = getRuntimeContext.getState(new ValueStateDescriptor[Double]("last-tempeatrue", classOf[Double])) //默认值为0.0
initTimeStampValueState = getRuntimeContext.getState(new ValueStateDescriptor[Long]("init-TimeStamp", classOf[Long])) //默认值为0
}
//每条数据都要走这个方法
override def processElement(i: SensorReading, context: KeyedProcessFunction[String, SensorReading, String]#Context, collector: Collector[String]): Unit = {
val lastTemp = lastTempraturValueState.value()
//没有定时器时initTime就是0,保存第一次温度上升的时间戳,方便后续删除,当定时器消失后进行clear,表明当时没有定时器了,整个过程只有一个定时器,
val initTime = initTimeStampValueState.value()
println("lastTemp" + lastTemp)
//当前温度和上次温度进行比较
if (i.temperature > lastTemp && initTime == 0) {
// 如果当前温度上升,并且没有定时器,则注册当前数据时间戳10s后的定时器,之前在这一步遇到了问题,记住要使用timerService().currentProcessingTime()
val currentTimeStamp = context.timerService().currentProcessingTime() + timeDuration
context.timerService().registerProcessingTimeTimer(currentTimeStamp)
println("注册定时器" + currentTimeStamp)
initTimeStampValueState.update(currentTimeStamp)
} else if (i.temperature > lastTemp && initTime != 0) {
//更新最新温度值
println("温度值" + i.temperature + "比上次温度值" + lastTemp + "高,更新最新温度")
} else if (i.temperature < lastTemp) {
//如果当前温度下降,则删除上次保存的初始状态的定时器
println("温度值" + i.temperature + "比上次温度值" + lastTemp + "低,但依然更新最新温度")
context.timerService().deleteProcessingTimeTimer(initTime)
println("销毁定时器" + initTime)
//当定时器消失后进行clear,表明当时没有定时器了,整个过程只有一个定时器
initTimeStampValueState.clear()
}
// 温度上升还是下降我们都保存上次的温度值,不进行清空而是进行赋值
lastTempraturValueState.update(i.temperature)
}
//定时器10s后触发,才执行这个方法
override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[String, SensorReading, String]#OnTimerContext, out: Collector[String]): Unit = {
//如果定时器没有被删除,那么就说明当前温度是连续10s上升的,否则之前就被删除了.定时器自己触发就不需要再删除了
out.collect("传感器" + ctx.getCurrentKey + "的定时器" + timestamp + "连续" + timeDuration + "秒上升")
//当定时器消失后进行clear,表明当时没有定时器了,整个过程只有一个定时器
initTimeStampValueState.clear()
}
}