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. ...
随机推荐
- 小程序 构建npm
1. 在项目文件夹下 打开cmd 窗口,输入: npm init 一直回车即可 2. 安装模板 npm i @vant/weapp -S --production 3. 在微信开发者工具,左上角工具中 ...
- 龙哥量化:MACD指标的金叉死叉,这样使用更准确(图解)
如果您需要代写技术指标公式, 请联系我. 龙哥QQ:591438821 龙哥微信:Long622889 本文的策略过于简单,你可以加一些更复杂的限制条件 1.水上金叉,可看涨; 2.水上死叉,是洗盘; ...
- 龙哥收集的Github资源——Python量化不要自己造轮子
打开github后,在搜索框中输入下面的项目作者及项目名称,然后点一下 All Github 搜索 格式 user:xxxxx in:name xxxxxxxxxxxxx 举例 user:Cken ...
- IM开发技术学习:揭秘微信朋友圈这种信息推流背后的系统设计
本文由徐宁发表于腾讯大讲堂,原题"程序员如何把你关注的内容推送到你眼前?揭秘信息流推荐背后的系统设计",有改动和修订. 1.引言 信息推流(以下简称"Feed流" ...
- spark (四) RDD概念
目录 1. RDD基本概念 1.1 弹性 1.2 分布式 1.3 数据集 1.4 数据抽象 1.5 不可变 1.6 可分区.并行计算 2. WordCount为例,看RDD特性 3. RDD的五大属性 ...
- 基于Redis有序集合实现滑动窗口限流
滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间段内的请求次数.通过动态地滑动窗口,可以动态调整限流的速率,以应对不同的流量变化. 整个限流可以概括 ...
- 题解:CF727F Polycarp's problems
link. 贪心做法. 本题贪心做法的实质就是用整数尽量多地抵消该整数后面的负数. 如果正着做,没有办法考虑全该数后面的所有负数,所以倒着做. 例如当前遍历到了 \(50\),此时序列如下: \[\d ...
- WPF BitmapSource /BitmapImage 获取像素点颜色
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 快速入门 DeepSeek-R1 大模型
国内最新的神级人工智能模型已经正式发布,没错,它就是备受瞩目的DeepSeek-R1大模型.今天,我们将对DeepSeek进行一个简单的了解,并探索如何快速使用和部署这个强大的工具.值得一提的是,De ...
- NFS v3及v4协议区别
本文分享自天翼云开发者社区<NFS v3及v4协议区别>,作者:章****凯 NFS v4相比v3,有部分功能的增强,如果应用需要实现如下功能,则必须使用NFS v4(建议和应用侧确实是否 ...