我们之前学习的转换算子是无法访问时间的时间戳信息和水位线信息的。而这些在一些应用场景下,极为重要,例如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)的更多相关文章

  1. 微信小程序把玩(三十六)Storage API

    原文:微信小程序把玩(三十六)Storage API 其实这个存储在新建Demo的时候就已经用到了就是存储就是那个logs日志,数据存储主要分为同步和异步 异步存储方法: 存数据 wx.setStor ...

  2. 强化学习(十六) 深度确定性策略梯度(DDPG)

    在强化学习(十五) A3C中,我们讨论了使用多线程的方法来解决Actor-Critic难收敛的问题,今天我们不使用多线程,而是使用和DDQN类似的方法:即经验回放和双网络的方法来改进Actor-Cri ...

  3. Expo大作战(三十六)--expo sdk api之 ImagePicker,ImageManipulator,Camera

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  4. Expo大作战(二十六)--expo sdk api之Video和WebBrowser

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

  5. Scala学习十六——XML处理

    一.本章要点 XML字面量<like>this</like>的类型为NodeSeq 可以在XML字面量中内嵌Scala代码 Node的child属性产出后代节点 Node的at ...

  6. 【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构

    redis 是使用 C 语言编写的,但是 C 语言是没有字典这个数据结构的,因此 C 语言自己使用结构体来自定义一个字典结构 typedef struct redisDb src\server.h 中 ...

  7. 智能车学习(十六)——CCD学习

    一.使用硬件 1.兰宙CCD四代      优点:可以调节运放来改变放大倍数      缺点:使用软排线(容易坏),CCD容易起灰,需要多次调节   2.野火K60底层     二.CCD硬件电路 ( ...

  8. Android JNI 学习(十):String Operations Api & Other Apis

    一.String Operations(字符串操作) 1. NewString jstring NewString(JNIEnv *env, const jchar *unicodeChars, js ...

  9. JavaWeb学习 (十六)————JSP中的九个内置对象

    一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...

  10. Spring学习十五----------Spring AOP API的Pointcut、advice及 ProxyFactoryBean相关内容

    © 版权声明:本文为博主原创文章,转载请注明出处 实例: 1.项目结构 2.pom.xml <project xmlns="http://maven.apache.org/POM/4. ...

随机推荐

  1. Spring 话题

    我从来不用 spring,项目再大也不会考虑 spring 那套模式.什么依赖注入控制反转,叠床架屋,对开发和运维可以说有害无益.上文 zz Spring 是一种反模式 - Inshua - 博客园 ...

  2. 2024年1月Java项目开发指南4:IDEA里配置MYSQL

    提前声明:文章首发博客园(cnblogs.com/mllt) 自动"搬家"(同步)到CSDN,如果博客园中文章发生修改是不会同步过去的,所以建议大家到我的博客园中查看 前提条件: ...

  3. Android7 以上https抓包(无需root)- virtualXposed + justTrustMe

    参考资料: https://www.cnblogs.com/boycelee/p/13418371.html 1. virtualXposed下载地址 https://github.com/andro ...

  4. Qt音视频开发41-人脸识别嵌入式

    一.前言 大概几年前搞过一套嵌入式linux上的人脸识别程序,当然人脸识别的核心算法并不是自己开发的,关于人脸识别算法这一块,虽然有众多的开源库可以用,甚至还可以用opencv搞算法训练深度学习之类的 ...

  5. Qt开源作品9-扁平化样式flatui

    一.前言 对于现在做前端开发人员来说,FlatUI肯定不陌生,最近几年扁平化的设计越来越流行,大概由于现在PC端和移动端的设备的分辨率越来越高,扁平化反而看起来更让人愉悦,而通过渐变色产生的质感色彩反 ...

  6. FFmpeg命令行选项

    如下内容取自官网文档"Documentation-ffmpeg"和"Documentation-ffmpeg-all" 1 帮助信息 如下选项适用于 ff 系列 ...

  7. vue3项目实战+element-plus

    记录自己搭建前端项目的学习过程和开发过程,希望一起学习进步 采用Vue3+element-plus+axios+vue-router+sass--(目前刚开始是用到了这些,随着开发慢慢更新) npm是 ...

  8. findHomography()函数详解

    indHomography: 计算多个二维点对之间的最优单映射变换矩阵 H(3行x3列) ,使用最小均方误差或者RANSAC方法 函数功能:找到两个平面之间的转换矩阵. Mat cv::findHom ...

  9. Python开发环境的构建:使用Anaconda与Pycharm

    Anaconda是一个科学计算环境,当在电脑上安装好Anaconda3以后,就相当于安装好了Python,还有一些常用的库,如numpy,scrip,matplotlib等库. (如果你这里没有安装a ...

  10. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践

    本文由爱奇艺技术团队原创分享,原题<构建通用WebSocket推送网关的设计与实践>,有优化和改动. 1.引言 丛所周之,HTTP协议是一种无状态.基于TCP的请求/响应模式的协议,即请求 ...