我们之前学习的转换算子是无法访问时间的时间戳信息和水位线信息的。而这些在一些应用场景下,极为重要,例如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. Avalonia 国际化之路:Resx 资源文件的深度应用与探索

    在当今全球化的软件开发浪潮中,应用的国际化(i18n)与本地化(L10n)显得尤为重要.Avalonia UI 作为一款强大的跨平台 UI 框架,为开发者提供了多种实现国际化的途径.其中,使用传统的 ...

  2. 技术实践|Hive数据迁移干货分享

    导语 Hive是基于Hadoop构建的一套数据仓库分析系统,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能.它的优点是可以通过类SQL语句快速实现简单的MapReduce统计,不 ...

  3. [转载] 十问 TiDB :关于架构设计的一些思考 TiDB

    做 TiDB 的缘起是从思考一个问题开始的:为什么在数据库领域有这么多永远也躲不开的坑?从 2015 年我们写下第一行代码,3 年以来我们迎面遇到无数个问题,一边思考一边做,尽量用最小的代价来快速奔跑 ...

  4. 用EwoMail开源版搭建邮箱服务器

    介绍: EwoMail是基于Linux的开源邮件服务器,支持一键搭建,集成了众多优秀稳定的组件,是一个快速部署.简单高效.安全稳定的邮件解决方案,支持电脑和手机的客户端,适合个人或邮箱功能需求少的企业 ...

  5. Qt血的教训/细数Qt开发的各种坑/又爱又恨/欢迎围观留言评论

    一.吐槽总结 搞Qt开发十几年了,最初从Qt4.6开始,一直追新到现在的6.7版本,中间经历过无数的血的教训,简直是又爱又恨.其实Qt挺好的,但是还是要忍不住吐槽一下,本人还是希望Qt发展的越来越好, ...

  6. Qt/C++音视频开发56-udp推流和拉流/组播和单播推流

    一.前言 之前已经实现了rtsp/rtmp推流,rtsp/rtmp/hls/flv/ws-flv/webrtc等拉流,这种一般都需要依赖一个独立的流媒体服务程序,有没有一种更便捷的方式不需要这种依赖, ...

  7. Redis安装服务到电脑

    1.直接在地址栏输入cmd回车打开命令窗口,输入 redis-server redis.windows.conf 然后回车 2.在cmd命令窗口输入以下命令并回车安装Windows本地服务 redis ...

  8. 2025-01-01:优质数对的总数Ⅰ。用go语言,给定两个整数数组 nums1 和 nums2,分别长度为 n 和 m,以及一个正整数 k。 如果 nums1 数组中的元素 nums1[i] 能被

    2025-01-01:优质数对的总数Ⅰ.用go语言,给定两个整数数组 nums1 和 nums2,分别长度为 n 和 m,以及一个正整数 k. 如果 nums1 数组中的元素 nums1[i] 能被 ...

  9. ASP.NET Core - 日志记录系统(二)

    本篇接着上一篇 [ASP.NET Core - 日志记录系统(一)] 往下讲,所以目录不是从 1 开始的. 2.4 日志提供程序 2.4.1 内置日志提供程序 ASP.NET Core 包括以下日志记 ...

  10. springboot之结合mybatis增删改查解析

    1. 场景描述 本节结合springboot2.springmvc.mybatis.swagger2等,搭建一个完整的增删改查项目,希望通过这个基础项目,能帮忙朋友快速上手springboot2项目. ...