Flink学习(十六) ProcessFunctionAPI(底层API)
我们之前学习的转换算子是无法访问时间的时间戳信息和水位线信息的。而这些在一些应用场景下,极为重要,例如MapFunction这样的map转换算子就无法访问时间戳或者当前事件的事件时间。
基于此,DataStreamAPI提供了一系列的Low-Level的转换算子,可以访问时间戳、watermark以及注册定时事件,还可以输出特定的一些事件,例如超时事件等等。ProcessFuntion用来构建事件驱动的应用以及实现自定义的业务逻辑(使用之前的window函数和转换算子是无法实现的),例如,Flink SQL就是使用ProcessFunction实现的。
Flink提供了8个Process Function:
1、ProcessFunction
2、KeyedProcessFuntion
3、CoProcessFunction
4、ProcessJoinFunction
5、BrodcastProcessFunction
6、KeyedBroadcastProcessFuntion
7、ProcessWindowFunction
8、ProcessAllWindowFunction
KeyedProcessFuntion
重点介绍并使用KeyedProcessFuntion
KeyedProcessFuntion用来操作KeyedStream、KeyedProessFunction会处理流的每一个元素,输出为0个,1个或者多个元素,所有的ProcessFunction都继承自RichFunction接口,所以都有open()、close()和getRuntimeContext()等方法,而KyedProcessFunction[KEY,IN,OUT]还额外提供了两个方法:
processElement(v:IN,ctx:Context,out:Collector[OUT]),流中的每一个元素都会调用这个方法,调用结果将会放在Collector数据类型中输出,Context可以方法元素的时间戳,元素的key,以及TimeServer时间事务,Context还可以将结果输出到别的流(side outpurts)。
onTimer(timestamp:Long,ctx:OnTimerContext,out:collector[OUT]) 是一个回调函数,当之前注册的定时器触发时调用。参数timestamp为定时器设定的触发的时间戳。Collector为输出结果的集合。OnTimerContext和processElement的Conetxt参数一样,提供了上下文的一些信息,例如定时器触发的时间信息(事件时间或者处理时间)
TimeServer和定时器(Timers)
Context和OnTImerContext所特有的TimeServer对象拥有以下方法:

1、返回当前处理事件
2、返回当前watermark的时间戳
3、删除之前注册的事件时间定时器,如果没有此时间戳的定时器,则不执行
4、删除之前注册处理时间定时器,如果没有这个时间戳的定时器,则不执行
5、会注册当前key的enven time定时器,当水位线大于等于定时器注册的时间时,触发定时器执行回调函数
6、会注册当前key的peocessing timer定时器,当processingtime到达定时时间时,触发timer,也就是onTimer方法
当定时器timer触发时,会执行回调函数onTimer() ,注意定时器timer只能在KyedStream上使用
案例测试:
package com.wyh.processFunctionApi
import org.apache.flink.api.common.state.{ValueState, ValueStateDescriptor}
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
//温度传感器读数样例类
case class SensorReading(id: String, timestamp: Long, temperature: Double)
object ProcessFunctionTest {
def main(args: Array[String]): Unit = {
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
val stream = env.socketTextStream("localhost", 7777)
//Transform操作
val dataStream: DataStream[SensorReading] = stream.map(data => {
val dataArray = data.split(",")
SensorReading(dataArray(0).trim, dataArray(1).trim.toLong, dataArray(2).trim.toDouble)
})
//===到来的数据是升序的,准时发车,用assignAscendingTimestamps
//指定哪个字段是时间戳 需要的是毫秒 * 1000
// .assignAscendingTimestamps(_.timestamp * 1000)
//===处理乱序数据
// .assignTimestampsAndWatermarks(new MyAssignerPeriodic())
//==底层也是周期性生成的一个方法 处理乱序数据 延迟1秒种生成水位 同时分配水位和时间戳 括号里传的是等待延迟的时间
.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor[SensorReading](Time.seconds(1)) {
override def extractTimestamp(t: SensorReading): Long = {
t.timestamp * 1000
}
})
val processedStream = dataStream.keyBy(_.id)
.process(new TempIncreAlert())
processedStream.print("process data")
dataStream.print("input data")
env.execute("window Test")
}
}
class TempIncreAlert() extends KeyedProcessFunction[String, SensorReading, String] {
//定义一个状态,用来保存上一个数据的温度值
//用懒加载的方式,一开始定义的时候我们还不执行,等到调用的时候去执行
//所有的状态都这么定义 当成一个变量直接用
lazy val lastTemp: ValueState[Double] = getRuntimeContext.getState(new ValueStateDescriptor[Double]("lastTemp", classOf[Double]))
//定义一个状态用来保存定时器的时间戳
lazy val currentTimer: ValueState[Long] = getRuntimeContext.getState(new ValueStateDescriptor[Long]("currentTimer", classOf[Long]))
//判断温度连续上升
//跟上一次数据进行比较 如果比较一直大 10秒种内进行报警
//注册一个定时器 把上一次的数据保存成当前的状态
override def processElement(value: SensorReading, ctx: KeyedProcessFunction[String, SensorReading, String]#Context, out: Collector[String]): Unit = {
//每来一条数据的时候,从状态中取出上一次的温度值
val preTemp = lastTemp.value()
var curTimerTs = currentTimer.value()
//更新温度值
lastTemp.update(value.temperature)
//加个if判断最开始的温度是否为0来判断是否是第一条数据 温度上升且没有设置过定时器,则注册定时器
if(preTemp==0.0){
println("这是第一条数据进来")
}else if ((value.temperature>preTemp) && (curTimerTs==0L)) {
val timerTs = ctx.timerService().currentProcessingTime() + 10000L
//传入当前时间加1 是时间戳
ctx.timerService().registerProcessingTimeTimer(timerTs)
currentTimer.update(timerTs)
} else if (value.temperature <= preTemp) {
//如果温度下降 或者是第一条数据 删除定时器
ctx.timerService().deleteProcessingTimeTimer(curTimerTs)
//删除定时器之后将状态清空
currentTimer.clear()
}
}
//在回调函数中执行定时器到的逻辑
//当前的时间 ctx上下文 out输出信息
override def onTimer(timestamp: Long, ctx: KeyedProcessFunction[String, SensorReading, String]#OnTimerContext, out: Collector[String]): Unit = {
//直接输出报警信息
out.collect(ctx.getCurrentKey + "温度连续上升")
//考虑真实情况,将状态都清空
currentTimer.clear()
}
}
在Linux命令行中使用命令 nc -lk 7777开启一个服务

先输入数据:
sensor_1,1547718199,39
等待10秒发现没有反应,继续输入数据,等待10秒发现,报警信息!

Flink学习(十六) ProcessFunctionAPI(底层API)的更多相关文章
- 微信小程序把玩(三十六)Storage API
原文:微信小程序把玩(三十六)Storage API 其实这个存储在新建Demo的时候就已经用到了就是存储就是那个logs日志,数据存储主要分为同步和异步 异步存储方法: 存数据 wx.setStor ...
- 强化学习(十六) 深度确定性策略梯度(DDPG)
在强化学习(十五) A3C中,我们讨论了使用多线程的方法来解决Actor-Critic难收敛的问题,今天我们不使用多线程,而是使用和DDQN类似的方法:即经验回放和双网络的方法来改进Actor-Cri ...
- Expo大作战(三十六)--expo sdk api之 ImagePicker,ImageManipulator,Camera
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- Expo大作战(二十六)--expo sdk api之Video和WebBrowser
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
- Scala学习十六——XML处理
一.本章要点 XML字面量<like>this</like>的类型为NodeSeq 可以在XML字面量中内嵌Scala代码 Node的child属性产出后代节点 Node的at ...
- 【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构
redis 是使用 C 语言编写的,但是 C 语言是没有字典这个数据结构的,因此 C 语言自己使用结构体来自定义一个字典结构 typedef struct redisDb src\server.h 中 ...
- 智能车学习(十六)——CCD学习
一.使用硬件 1.兰宙CCD四代 优点:可以调节运放来改变放大倍数 缺点:使用软排线(容易坏),CCD容易起灰,需要多次调节 2.野火K60底层 二.CCD硬件电路 ( ...
- Android JNI 学习(十):String Operations Api & Other Apis
一.String Operations(字符串操作) 1. NewString jstring NewString(JNIEnv *env, const jchar *unicodeChars, js ...
- JavaWeb学习 (十六)————JSP中的九个内置对象
一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...
- Spring学习十五----------Spring AOP API的Pointcut、advice及 ProxyFactoryBean相关内容
© 版权声明:本文为博主原创文章,转载请注明出处 实例: 1.项目结构 2.pom.xml <project xmlns="http://maven.apache.org/POM/4. ...
随机推荐
- Gitlab:Restoring PostgreSQL database gitlabhq_production ... ERROR: must be owner of extension pg_trgm
Restoring PostgreSQL database gitlabhq_production ... ERROR: must be owner of extension pg_trgm ERRO ...
- 技术实践|Hive数据迁移干货分享
导语 Hive是基于Hadoop构建的一套数据仓库分析系统,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能.它的优点是可以通过类SQL语句快速实现简单的MapReduce统计,不 ...
- SpringBoot 集成Swagger后提通过http://localhost:8001/swagger-ui.html#/访问得不到页面
SpringBoot 集成Swagger后提通过http://localhost:8001/swagger-ui.html#/访问得不到页面: spring boot 集成 swagger2步骤: ...
- 即时通讯技术文集(第38期):IM代码入门实践(Part2) [共15篇]
为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第38 期. [- 1 -] 高仿Android版手机QQ首页侧滑菜单源码 [附件下载] [链接 ...
- 长连接网关技术专题(十一):揭秘腾讯公网TGW网关系统的技术架构演进
本文由腾讯技术团队peter分享,原题"腾讯网关TGW架构演进之路",下文进行了排版和内容优化等. 1.引言 TGW全称Tencent Gateway,是一套实现多网统一接入,支持 ...
- IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!
本文由IBM开发者社区分享,有较多修订和改动. 1.引言 在当今移动网络时代,手机流量和电量是宝贵的资源,对于移动端最常见的即时通讯IM应用,由于实时通信基于Socket长连接,它对于流量和电量的需求 ...
- 记录使用socket.io的使用
今天记录一下node.js的egg框架搭建的socket.io,前端联合使用 首先得引入socket.io的js,我这边是用的下载到本地的一个js 引入:const io = require('../ ...
- 新版 Cursor 把其他 AI 编程工具按在地上摩擦了!
大家好,我是汤师爷~ AI编程助手Cursor背后的Anysphere公司刚刚完成了1亿美元的B轮融资,估值直接飙升至26亿美元. 四个月前,这家公司刚拿下6000万美元,估值还只有4亿美元.如今,增 ...
- http请求工具类 HttpClient4Util
1.依赖 <!-- httpclient --> <dependency> <groupId>org.apache.httpcomponents</group ...
- 第一届启航杯网络安全大赛部分wp
第一届启航杯 WEB Easy include <?php error_reporting(0); //flag in flag.php $file=$_GET['fil e']; if(iss ...