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 ...
 
随机推荐
- 转-JavaWeb三大组件之Listener监听器
			
JavaWeb三大组件之Listener监听器一.概述1,它是一个接口,内容由我们来实现 2,它需要注册,例如注册在按钮上 3,监听器中的方法,会在特殊事件发生时被调用 二.JavaWeb中的监听器1 ...
 - WebStorm 关联 TFS(转)
			
1.下载插件 TFS integration 2.链接TFS 服务器 3.创建工作区 4. 5.选择一个 工作环境 6.最重要的有点是在VCS里面要选择一个默认的提交方式!!!
 - ES--05
			
第四十一讲!分词器内部组成 内置分词器 课程大纲 1.什么是分词器 切分词语,normalization(提升recall召回率) 给你一段句子,然后将这段句子拆分成一个一个的单个的单词,同时对每个单 ...
 - ansible笔记(9):常用模块之包管理模块
			
ansible笔记():常用模块之包管理模块 yum_repository模块 yum_repository模块可以帮助我们管理远程主机上的yum仓库. 此处我们介绍一些yum_repository模 ...
 - 持续集成之④:GitLab触发jenkins构建项目
			
持续集成之④:GitLab触发jenkins构建项目 一:目的为在公司的测试环境当中一旦开发向gitlab仓库提交成功代码,gitlab通知jenkins进行构建项目.代码质量测试然后部署至测试环境, ...
 - Light OJ 1095
			
题意: 给你 N 个数, 总共有 N! 种排列, 现在 要你统计前 M 个数 刚好 有K 个数 在原来的位置上 的排列个数 思路: 首先 M 中选 K C(m,k): 则 共 剩下 n - k 个数, ...
 - python创建udp服务端和客户端
			
1.udp服务端server from socket import * from time import ctime HOST = '' PORT = 8888 BUFSIZ = 1024 ADDR ...
 - GoLand使用
			
# 不定期更新 什么是GoLand GoLand是JetBrains出品的一个Go语言IDE,JB的IDE有多好用我想很多程序员都知道,个人感觉唯一的缺点就是比较大(因为功能多) 希望大家多多支持正版 ...
 - python之__call__()
			
__call__ 在Python中,函数其实是一个对象: >>> f = abs >>> f.__name__ 'abs' >>> f(-123) ...
 - linux进程内存布局
			
一个程序本质上都是由 BSS 段.data段.text段三个组成的.这样的概念在当前的计算机程序设计中是很重要的一个基本概念,而且在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分 ...