我们之前学习的转换算子是无法访问时间的时间戳信息和水位线信息的。而这些在一些应用场景下,极为重要,例如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. 中电金信技术实践|Redis哨兵原理及安装部署分享

    ​ 导语:本文主要围绕redis Sentinel的基本概念.部署Redis Sentinel模式和其相关的API等内容进行介绍,并讲述哨兵与主从关系的区别,以及哨兵机制是怎么实现高可用的,希望可以与 ...

  2. 解决编译redis报错zmalloc.h:50:10: fatal error: jemalloc/jemalloc.h: No such file or directory

    编译redis时报错:zmalloc.h:50:10: fatal error: jemalloc/jemalloc.h: No such file or directory,执行: # sudo m ...

  3. 带宽计算-大B和小B的区别

    在计算机网络.IDC机房中,其宽带速率的单位用bps(或b/s)表示:换算关系为:1Byte=8bit 1B=8b    ---- 1B/s=8b/s(或1Bps=8bps) 1KB=1024B    ...

  4. debian/ubuntu系统vi无法删除字符的解决办法

    之前在 Linux 下操作,一直使用的是 Centos 系统,使用 vi 编辑命令一直很顺畅. 最近,入手了一台 debian 操作系统的 vps.在操作 vi 命令时,发现当输入 i 要进行文件编辑 ...

  5. Python中定位元素包含文本信息的详细解析与代码示例

    在Python编程中,特别是在进行网页自动化测试或数据抓取时,定位包含特定文本信息的元素是一个常见的需求.通过合适的工具和库,可以高效地查找和操作这些元素.本文将详细介绍如何在Python中定位包含文 ...

  6. .NET 9 增强 OpenAPI 规范

    在 .NET 9 的更新中,微软增强了原生 OpenAPI.这一变化表明 .NET 正在更加拥抱开放标准,同时让开发者体验更加轻松高效.本文将探讨为何进行这一更改.OpenAPI 的优势,以及如何在 ...

  7. Qt/C++实现帧同步播放器/硬解码GPU绘制/超低资源占用/支持8K16K/支持win/linux/mac/嵌入式/国产OS等

    一.前言 首先泼一盆冷水,在不同的电脑上实现完完全全的帧同步理论上是不可能的,市面上所有号称帧同步的播放器,同一台电脑不同拼接视频可以通过合并成一张图片来绘制实现完完全全的帧同步,不同电脑,受限于网络 ...

  8. Web网页端IM产品RainbowChat-Web的v7.0版已发布

    一.关于RainbowChat-Web RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIM ...

  9. 测试直播伴侣和OBS对透明度的支持哪个好?

    测试直播伴侣和OBS对透明度的支持哪个好? 抖音无人直播,用抖音弹幕助手 测试直播伴侣和OBS对透明度的支持哪个好?抖音无人直播,用抖音弹幕助手 ​测试地址1 ​测试地址2

  10. java多线程与线程池-copy

    1. 场景描述 以前多线程也常用,这次因需再页面上用到多线程,如下图,总结下,有需要的朋友可以参考下. 2. 解决方案 2.1 线程池概念 线程池官方定义不说了,通俗说下:池子的概念,事先(预定义)创 ...