Flink--time-window 的高级用法


1.现实世界中的时间是不一致的,在 flink 中被划分为事件时间,提取时间,处理时间三种。
2.如果以 EventTime 为基准来定义时间窗口那将形成 EventTimeWindow,要求消息本身就应该携带 EventTime
3.如果以 IngesingtTime 为基准来定义时间窗口那将形成 IngestingTimeWindow,以 source 的 systemTime 为准。
4.如果以 ProcessingTime 基准来定义时间窗口那将形成 ProcessingTimeWindow,以 operator 的 systemTime 为准。
EventTime

需求:
EventTime 3 数据:
1527911155000,boos1,pc1,100.0 1527911156000,boos2,pc1,200.0 1527911157000,boos1,pc1,300.0 1527911158000,boos2,pc1,500.0 1527911159000,boos1,pc1,600.0 1527911160000,boos1,pc1,700.0 1527911161000,boos2,pc2,700.0 1527911162000,boos2,pc2,900.0 1527911163000,boos2,pc2,1000.0 1527911164000,boos2,pc2,1100.0 1527911165000,boos1,pc2,1100.0 1527911166000,boos2,pc2,1300.0 1527911167000,boos2,pc2,1400.0 1527911168000,boos2,pc2,1600.0
1527911169000,boos1,pc2,1300.0
代码实现:
object EventTimeExample {
def main(args: Array[String]) {
//1.创建执行环境,并设置为使用 EventTime
val env = StreamExecutionEnvironment.getExecutionEnvironment
//置为使用 EventTime
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
//2.创建数据流,并进行数据转化
val source = env.socketTextStream("localhost", 9999)
case class SalePrice(time: Long, boosName: String, productName: String, price: Double)
val dst1: DataStream[SalePrice] = source.map(value => {
val columns = value.split(",")
SalePrice(columns(0).toLong, columns(1), columns(2), columns(3).toDouble)
})
//3.使用 EventTime 进行求最值操作
val dst2: DataStream[SalePrice] = dst1
//提取消息中的时间戳属性
.assignAscendingTimestamps(_.time)
.keyBy(_.productName)
.timeWindow(Time.seconds(3))//设置 window 方法一
.max("price")
//4.显示结果
dst2.print()
//5.触发流计算
env.execute()
}
}
当前代码理论上看没有任何问题,在实际使用的时候就会出现很多问题,甚至接 收不到数据或者接收到的数据是不准确的;这是因为对于 flink 最初设计的时 候,就考虑到了网络延迟,网络乱序等问题,所以提出了一个抽象概念基座水印
(WaterMark);

水印分成两种形式:
第一种:

第二种:

所以,我们需要考虑到网络延迟的状况,那么代码中就需要添加水印操作:
object EventTimeOperator {
def main(args: Array[String]): Unit = {
//创建执行环境,并设置为使用EventTime
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(1)//注意控制并发数
//置为使用EventTime
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)
val source = env.socketTextStream("localhost", 9999)
val dst1: DataStream[SalePrice] = source.map(value => {
val columns = value.split(",")
SalePrice(columns(0).toLong, columns(1), columns(2), columns(3).toDouble)
})
//todo 水印时间 assignTimestampsAndWatermarks
val timestamps_data = dst1.assignTimestampsAndWatermarks(new AssignerWithPeriodicWatermarks[SalePrice]{
var currentMaxTimestamp:Long = 0
val maxOutOfOrderness = 2000L //最大允许的乱序时间是2s
var wm : Watermark = null
val format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
override def getCurrentWatermark: Watermark = {
wm = new Watermark(currentMaxTimestamp - maxOutOfOrderness)
wm
}
override def extractTimestamp(element: SalePrice, previousElementTimestamp: Long): Long = {
val timestamp = element.time
currentMaxTimestamp = Math.max(timestamp, currentMaxTimestamp)
}
})
val data: KeyedStream[SalePrice, String] = timestamps_data.keyBy(line => line.productName)
val window_data: WindowedStream[SalePrice, String, TimeWindow] = data.timeWindow(Time.seconds(3))
val apply: DataStream[SalePrice] = window_data.apply(new MyWindowFunc)
apply.print()
env.execute()
}
}
case class SalePrice(time: Long, boosName: String, productName: String, price: Double)
class MyWindowFunc extends WindowFunction[SalePrice , SalePrice , String, TimeWindow]{
override def apply(key: String, window: TimeWindow, input: Iterable[SalePrice], out: Collector[SalePrice]): Unit = {
val seq = input.toArray
val take: Array[SalePrice] = seq.sortBy(line => line.price).reverse.take(1)
for(info <- take){
out.collect(info)
}
}
}

ProcessingTime
对于 processTime 而言,是 flink 处理数据的时间,所以就不关心发过来的数据 是不是有延迟操作,只关心数据具体的处理时间,所以不需要水印处理,操作相 对来说简单了很多
object ProcessingTimeExample {
def main(args: Array[String]) {
//创建执行环境,并设置为使用EventTime
val env = StreamExecutionEnvironment.getExecutionEnvironment
env.setParallelism(2)//注意控制并发数
//置为使用ProcessingTime
env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)
val source = env.socketTextStream("localhost", 9999)
case class SalePrice(time: Long, boosName: String, productName: String, price: Double)
val dst1: DataStream[SalePrice] = source.map(value => {
val columns = value.split(",")
SalePrice(columns(0).toLong, columns(1), columns(2), columns(3).toDouble)
})
//processTime不需要提取消息中的时间
// val timestamps_data: DataStream[SalePrice] = dst1.assignAscendingTimestamps(line => line.time)
val keyby_data: KeyedStream[SalePrice, String] = dst1.keyBy(line => line.productName)
//TODO 窗口事件是:TumblingProcessingTimeWindows
val window_data: WindowedStream[SalePrice, String, TimeWindow] = keyby_data.window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
val max_price: DataStream[SalePrice] = window_data.max("price")
max_price.print()
env.execute()
}
}
Flink--time-window 的高级用法的更多相关文章
- nmap命令-----高级用法
探测主机存活常用方式 (1)-sP :进行ping扫描 打印出对ping扫描做出响应的主机,不做进一步测试(如端口扫描或者操作系统探测): 下面去扫描10.0.3.0/24这个网段的的主机 nmap ...
- Block高级用法:Block传值UI_12(3)
1.简单复习Block的定义.赋值.调用做学习传值铺垫: //声明一个函数 无返无参void printfHello(int a);//函数的实现void printfHello(int a){ ...
- Python之Requests的高级用法
# 高级用法 本篇文档涵盖了Requests的一些更加高级的特性. ## 会话对象 会话对象让你能够跨请求保持某些参数.它也会在同一个Session实例发出的所有请求之间保持cookies. 会话对象 ...
- Requests库的文档高级用法
高级用法 本篇文档涵盖了 Requests 的一些高级特性. 会话对象 会话对象让你能够跨请求保持某些参数.它也会在同一个 Session 实例发出的所有请求之间保持 cookie, 期间使用 url ...
- Fiddler 高级用法:Fiddler Script 与 HTTP 断点调试
转载自 https://my.oschina.net/leejun2005/blog/399108 1.Fiddler Script 1.1 Fiddler Script简介 在web前端开发的过程中 ...
- Selenium WebDriver高级用法
Selenium GitHub地址 选择合适的WebDrvier WebDriver是一个接口,它有几种实现,分别是HtmlUnitDrvier.FirefoxDriver.InternetExplo ...
- 爬虫—Requests高级用法
Requests高级用法 1.文件上传 我们知道requests可以模拟提交一些数据.假如有的网站需要上传文件,我们也可以用requests来实现. import requests files = { ...
- python requests 高级用法
高级用法 本篇文档涵盖了 Requests 的一些高级特性. 会话对象 会话对象让你能够跨请求保持某些参数.它也会在同一个 Session 实例发出的所有请求之间保持 cookie, 期间使用 url ...
- doT的高级用法及loadData的使用
本文出自APICloud官方论坛, 感谢论坛版主 gp3098的分享. 之前直接把模板写在页面底部的script标签内的,但是现在不同. 使用了doT.js配合api的loadData方法,整个页面就 ...
- Nmap在实战中的高级用法(详解)
@ 目录 Nmap在实战中的高级用法(详解) Nmap简单的扫描方式: 一.Nmap高级选项 1.查看本地路由与接口 2.指定网口与IP地址 3.定制探测包 二.Nmap扫描防火墙 1.SYN扫描 2 ...
随机推荐
- webp 图形文件操作工具包 win32 (编译 libwebp-20171228-664c21dd 版本)
源码下载地址 https://chromium.googlesource.com/webm/libwebp/ 版本 libwebp-20171228-664 ...
- v-on 绑定自定义事件
每个 Vue 实例都实现了事件接口,即: 使用 $on(eventName) 监听事件 使用 $emit(eventName) 触发事件 Vue 的事件系统与浏览器的 EventTarget API ...
- 通过python统计nginx日志定位php网站响应慢的问题
# 公司网站反映很慢,可能是一些页面的访问方法或者页面引起,通过程序统计nginx访问日志的页面和具体的action方法访问次数以及平均响应时间可以为程序开发的同事提供参考定位具体的代码 # 默认的n ...
- JDK的安装及环境变量配置
JDK的安装及环境变量配置 JDK解释:直达详细解释. 1.JDK下载地址:点击直达官网下载 进入后,如图1,点击图中红框DOWNLOAD按钮进入下载页 进入下载页后,在下载也底端,根据自己的需求下载 ...
- HBase在HDFS上的目录介绍
总所周知,HBase 是天生就是架设在 HDFS 上,在这个分布式文件系统中,HBase 是怎么去构建自己的目录树的呢? 第一,介绍系统级别的目录树. 一.0.94-cdh4.2.1版本 系统级别的一 ...
- zookeeper的三种安装模式
zookeeper的安装分为三种模式:单机模式.集群模式和伪集群模式. 1.单机模式 首先,从Apache官网下载一个Zookeeper稳定版本,本次教程采用的是zookeeper-3.4.9版本. ...
- postgresql 触发器 更新操作
1 前言 功能需求:当一张表格某个字段变化,另一张表某个字段写入该值 2 代码 CREATE OR REPLACE FUNCTION "public"."synStatu ...
- 使用第三方组件(django-redis)创建连接池
settings里面: ##redis配置CACHES={ 'default':{ 'BACKEND':'django_redis.cache.RedisCache', 'LOCATION':'red ...
- Modbus库开发笔记之一:实现功能的基本设计
Modbus作为开放式的工业通讯协议,在各种工业设备中应用极其广泛.本人也使用Modbus通讯很多年了,或者用现成的,或者针对具体应用开发,一直以来都想要开发一个比较通用的协议栈能在后续的项目中复用, ...
- Vue2.0 新手完全填坑攻略—从环境搭建到发布
http://www.open-open.com/lib/view/open1476240930270.html https://jingyan.baidu.com/article/91f5db1b2 ...