Flink的窗口机制

1.窗口概述

在流处理应用中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理。当然我们可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处理,例如:在过去的1分钟内有多少用户点击了我们的网页。在这种情况下,我们必须定义一个窗口,用来收集最近一分钟内的数据,并对这个窗口内的数据进行计算。

流式计算是一种被设计用于处理无限数据集的数据处理引擎,而无限数据集是指一种不断增长的本质上无限的数据集,而Window窗口是一种切割无限数据为有限块进行处理的手段。

在Flink中, 窗口(window)是处理无界流的核心. 窗口把流切割成有限大小的多个"存储桶"(bucket), 我们在这些桶上进行计算。

2.窗口分类

窗口分为2类:

  1. 基于时间的窗口(时间驱动)

  2. 基于元素个数的(数据驱动)

基于时间的窗口

时间窗口包含一个开始时间戳(包括)和结束时间戳(不包括), 这两个时间戳一起限制了窗口的尺寸.

在代码中, Flink使用TimeWindow这个类来表示基于时间的窗口. 这个类提供了key查询开始时间戳和结束时间戳的方法, 还提供了针对给定的窗口获取它允许的最大时间差的方法(maxTimestamp())

时间窗口又分4种:

滚动窗口(Tumbling Windows)

滚动窗口有固定的大小, 窗口与窗口之间不会重叠也没有缝隙.比如,如果指定一个长度为5分钟的滚动窗口, 当前窗口开始计算, 每5分钟启动一个新的窗口.

滚动窗口能将数据流切分成不重叠的窗口,每一个事件只能属于一个窗口

java代码

  1. package com.flink.day04_window;
  2. import org.apache.flink.api.common.functions.FlatMapFunction;
  3. import org.apache.flink.api.java.tuple.Tuple2;
  4. import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
  5. import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
  6. import org.apache.flink.streaming.api.windowing.time.Time;
  7. import org.apache.flink.util.Collector;
  8. import java.util.Arrays;
  9. /**
  10. * @description: TODO 滚动时间窗口
  11. * 1. 时间间隔可以通过: Time.milliseconds(x), Time.seconds(x), Time.minutes(x),等等来指定.
  12. * 2. 我们传递给window函数的对象叫窗口分配器.
  13. * @author: HaoWu
  14. * @create: 2021年05月14日
  15. */
  16. public class Flink01_Window_Tumbling {
  17. public static void main(String[] args) throws Exception {
  18. StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
  19. env.setParallelism(2);
  20. env.socketTextStream("localhost",9999)
  21. .flatMap(new FlatMapFunction<String, Tuple2<String,Integer>>() {
  22. @Override
  23. public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
  24. // String[] datas = value.split(",");
  25. // for (int i = 0; i < datas.length-1; i++) {
  26. // out.collect(Tuple2.of(datas[i],1));
  27. // }
  28. Arrays.stream(value.split(",")).forEach(word -> out.collect(Tuple2.of(word, 1)));
  29. }
  30. })
  31. .keyBy(t->t.f0)
  32. .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
  33. .sum(1)
  34. .print();
  35. env.execute();
  36. }
  37. }

说明:

  1. 时间间隔可以通过: Time.milliseconds(x), Time.seconds(x), Time.minutes(x),等等来指定.

  2. 我们传递给window函数的对象叫窗口分配器.

滑动窗口(Sliding Windows)

与滚动窗口一样, 滑动窗口也是有固定的长度. 另外一个参数我们叫滑动步长, 用来控制滑动窗口启动的频率.

所以, 如果滑动步长小于窗口长度, 滑动窗口会重叠. 这种情况下, 一个元素可能会被分配到多个窗口中

例如, 滑动窗口长度10分钟, 滑动步长5分钟, 则, 每5分钟会得到一个包含最近10分钟的数据.

java代码

  1. package com.flink.day04_window;
  2. import org.apache.flink.api.common.functions.FlatMapFunction;
  3. import org.apache.flink.api.java.tuple.Tuple2;
  4. import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
  5. import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
  6. import org.apache.flink.streaming.api.windowing.assigners.SlidingProcessingTimeWindows;
  7. import org.apache.flink.streaming.api.windowing.time.Time;
  8. import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
  9. import org.apache.flink.util.Collector;
  10. import java.util.Arrays;
  11. /**
  12. * @description: TODO 滑动窗口
  13. * @author: HaoWu
  14. * @create: 2021年05月17日
  15. */
  16. public class Flink02_Window_Sliding {
  17. public static void main(String[] args) throws Exception {
  18. StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
  19. env.setParallelism(2);
  20. env.socketTextStream("localhost",9999)
  21. .flatMap(new FlatMapFunction<String, Tuple2<String,Integer>>() {
  22. @Override
  23. public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
  24. String[] datas = value.split(",");
  25. Arrays.stream(datas).forEach(ele->{out.collect(Tuple2.of(ele,1));});
  26. }
  27. })
  28. .keyBy(t->t.f0)
  29. .window(SlidingProcessingTimeWindows.of(Time.seconds(5),Time.seconds(1)))
  30. .process(new ProcessWindowFunction<Tuple2<String, Integer>, String, String, TimeWindow>() {
  31. Integer count=0;
  32. @Override
  33. public void process(String s, Context context, Iterable<Tuple2<String, Integer>> elements, Collector<String> out) throws Exception {
  34. for (Tuple2<String, Integer> element : elements) {
  35. count++;
  36. }
  37. long start = context.window().getStart();
  38. long end = context.window().getEnd();
  39. out.collect("当前key:"+s+",窗口:["+start+","+end+"),count:"+count);
  40. }
  41. }).print();
  42. env.execute();
  43. }
  44. }
会话窗口(Session Windows)

会话窗口分配器会根据活动的元素进行分组. 会话窗口不会有重叠, 与滚动窗口和滑动窗口相比, 会话窗口也没有固定的开启和关闭时间.

如果会话窗口有一段时间没有收到数据, 会话窗口会自动关闭, 这段没有收到数据的时间就是会话窗口的gap(间隔).

我们可以配置静态的gap, 也可以通过一个gap extractor 函数来定义gap的长度. 当时间超过了这个gap, 当前的会话窗口就会关闭, 后序的元素会被分配到一个新的会话窗口.

示例代码

  1. 1.静态gap
  2. .window(ProcessingTimeSessionWindows.withGap(Time.seconds(10)))
  3. 2.动态gap
  4. .window(ProcessingTimeSessionWindows.withDynamicGap(new SessionWindowTimeGapExtractor<Tuple2<String, Long>>() {
  5. @Override
  6. public long extract(Tuple2<String, Long> element) { // 返回 gap值, 单位毫秒
  7. return element.f0.length() * 1000;
  8. }
  9. }))

创建原理

因为会话窗口没有固定的开启和关闭时间, 所以会话窗口的创建和关闭与滚动,滑动窗口不同. 在Flink内部, 每到达一个新的元素都会创建一个新的会话窗口, 如果这些窗口彼此相距比较定义的gap小, 则会对他们进行合并. 为了能够合并, 会话窗口算子需要合并触发器和合并窗口函数: ReduceFunction, AggregateFunction, or ProcessWindowFunction

全局窗口(Global Windows)

全局窗口分配器会分配相同key的所有元素进入同一个 Global window. 这种窗口机制只有指定自定义的触发器时才有用. 否则, 不会做任务计算, 因为这种窗口没有能够处理聚集在一起元素的结束点.

示例代码:

  1. .window(GlobalWindows.create());

基于元素个数的窗口

按照指定的数据条数生成一个Window,与时间无关

滚动窗口

默认的CountWindow是一个滚动窗口,只需要指定窗口大小即可,当元素数量达到窗口大小时,就会触发窗口的执行。

示例代码

  1. .countWindow(3)

说明:那个窗口先达到3个元素, 哪个窗口就关闭. 不影响其他的窗口.

滑动窗口

滑动窗口和滚动窗口的函数名是完全一致的,只是在传参数时需要传入两个参数,一个是window_size,一个是sliding_size。下面代码中的sliding_size设置为了2,也就是说,每收到两个相同key的数据就计算一次,每一次计算的window范围最多是3个元素。

  1. 实例代码
  2. .countWindow(3, 2)

3.窗口函数

前面指定了窗口的分配器, 接着我们需要来指定如何计算, 这事由window function来负责. 一旦窗口关闭, window function 去计算处理窗口中的每个元素.

window function 可以是ReduceFunction,AggregateFunction,or ProcessWindowFunction中的任意一种.

ReduceFunction,AggregateFunction更加高效, 原因就是Flink可以对到来的元素进行增量聚合 ProcessWindowFunction 可以得到一个包含这个窗口中所有元素的迭代器, 以及这些元素所属窗口的一些元数据信息.

ProcessWindowFunction不能被高效执行的原因是Flink在执行这个函数之前, 需要在内部缓存这个窗口上所有的元素

ReduceFunction(增量聚合函数)
  1. package com.flink.day04_window;
  2. import org.apache.flink.api.common.functions.FlatMapFunction;
  3. import org.apache.flink.api.common.functions.ReduceFunction;
  4. import org.apache.flink.api.java.tuple.Tuple2;
  5. import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
  6. import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
  7. import org.apache.flink.streaming.api.windowing.time.Time;
  8. import org.apache.flink.util.Collector;
  9. import java.util.Arrays;
  10. /**
  11. * @description: TODO 窗口函数之增量聚合函数:reduce
  12. * 注意:第一个元素不会进入reduce方法
  13. * @author: HaoWu
  14. * @create: 2021年05月17日
  15. */
  16. public class Flink03_Window_Function_ReduceFunction {
  17. public static void main(String[] args) throws Exception {
  18. StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
  19. env.setParallelism(2);
  20. env.socketTextStream("localhost",9999)
  21. .flatMap(new FlatMapFunction<String, Tuple2<String,Integer>>() {
  22. @Override
  23. public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
  24. Arrays.stream(value.split(",")).forEach(word -> out.collect(Tuple2.of(word, 1)));
  25. }
  26. })
  27. .keyBy(t->t.f0)
  28. .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
  29. // value1是上次聚合的结果. 所以遇到每个窗口的第一个元素时, 这个函数不会进来
  30. .reduce(new ReduceFunction<Tuple2<String, Integer>>() {
  31. @Override
  32. public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) throws Exception {
  33. System.out.println(value1+"----------"+value2);
  34. return Tuple2.of(value1.f0,value1.f1+value2.f1);
  35. }
  36. }).print();
  37. env.execute();
  38. }
  39. }
AggregateFunction(增量聚合函数)
  1. package com.flink.day04_window;
  2. import org.apache.flink.api.common.functions.AggregateFunction;
  3. import org.apache.flink.api.common.functions.FlatMapFunction;
  4. import org.apache.flink.api.java.tuple.Tuple2;
  5. import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
  6. import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
  7. import org.apache.flink.streaming.api.windowing.time.Time;
  8. import org.apache.flink.util.Collector;
  9. import java.util.Arrays;
  10. /**
  11. * @description: TODO 窗口函数之增量聚合函数:aggregate
  12. * @author: HaoWu
  13. * @create: 2021年05月25日
  14. */
  15. public class Flink04_Window_Function_AggregateFunction {
  16. public static void main(String[] args) throws Exception {
  17. //1.创建执行环境
  18. StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
  19. //2.逻辑处理
  20. env.socketTextStream("localhost", 9999)
  21. .flatMap(new FlatMapFunction<String, Tuple2<String, Long>>() {
  22. @Override
  23. public void flatMap(String value, Collector<Tuple2<String, Long>> out) throws Exception {
  24. String[] arr = value.split(",");
  25. Arrays.stream(arr).forEach(x -> out.collect(Tuple2.of(x, 1L)));
  26. }
  27. })
  28. .keyBy(x -> x.f0)
  29. .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
  30. .aggregate(new AggregateFunction<Tuple2<String, Long>, Long, Long>() {
  31. // 创建累加器: 初始化中间值
  32. @Override
  33. public Long createAccumulator() {
  34. System.out.println("createAccumulator");
  35. return 0L;
  36. }
  37. // 累加器操作
  38. @Override
  39. public Long add(Tuple2<String, Long> value, Long accumulator) {
  40. System.out.println("add");
  41. return accumulator + value.f1;
  42. }
  43. // 获取结果
  44. @Override
  45. public Long getResult(Long accumulator) {
  46. System.out.println("getResult");
  47. return accumulator;
  48. }
  49. // 累加器的合并: 只有会话窗口才会调用
  50. @Override
  51. public Long merge(Long a, Long b) {
  52. System.out.println("merge");
  53. return a + b;
  54. }
  55. }
  56. ).print();
  57. //3.执行程序
  58. env.execute();
  59. }
  60. }
ProcessWindowFunction(全窗口函数)
  1. package com.flink.day04_window;
  2. import org.apache.flink.api.common.functions.FlatMapFunction;
  3. import org.apache.flink.api.java.tuple.Tuple2;
  4. import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
  5. import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
  6. import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
  7. import org.apache.flink.streaming.api.windowing.time.Time;
  8. import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
  9. import org.apache.flink.util.Collector;
  10. import java.util.Arrays;
  11. /**
  12. * @description: TODO 窗口函数之 全窗口函数
  13. * @author: HaoWu
  14. * @create: 2021年05月25日
  15. */
  16. public class Flink05_Window_Function_ProcessWindowFunction {
  17. public static void main(String[] args) throws Exception {
  18. //1.创建执行环境
  19. StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
  20. env.setParallelism(2);
  21. //2.逻辑处理
  22. env.socketTextStream("localhost", 9999)
  23. .flatMap(new FlatMapFunction<String, Tuple2<String, Long>>() {
  24. @Override
  25. public void flatMap(String value, Collector<Tuple2<String, Long>> out) throws Exception {
  26. String[] arr = value.split(",");
  27. Arrays.stream(arr).forEach(x -> out.collect(Tuple2.of(x, 1L)));
  28. }
  29. })
  30. .keyBy(x -> x.f0)
  31. .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
  32. .process(new ProcessWindowFunction<Tuple2<String, Long>, Tuple2<String,Long>, String, TimeWindow>() {
  33. // 参数1: key 参数2: 上下文对象 参数3: 这个窗口内所有的元素 参数4: 收集器, 用于向下游传递数据
  34. @Override
  35. public void process(String key, Context context, Iterable<Tuple2<String, Long>> elements, Collector<Tuple2<String, Long>> out) throws Exception {
  36. System.out.println("窗口开始:"+context.window().getStart());
  37. long sum = 0L;
  38. for (Tuple2<String, Long> t : elements) {
  39. sum += t.f1;
  40. }
  41. out.collect(Tuple2.of(key, sum));
  42. System.out.println("窗口结束:"+context.window().getEnd());
  43. }
  44. }).print();
  45. //3.执行程序
  46. env.execute();
  47. }
  48. }

4.Key和No Key的窗口区别

其实, 在用window前首先需要确认应该是在keyBy后的流上用, 还是在没有keyBy的流上使用.

在keyed streams上使用窗口, 窗口计算被并行的运用在多个task上, 可以认为每个task都有自己单独窗口. 正如前面的代码所示.

在非non-keyed stream上使用窗口, 流的并行度只能是1, 所有的窗口逻辑只能在一个单独的task上执行.

示例代码

  1. .windowAll(TumblingProcessingTimeWindows.of(Time.seconds(10)))

需要注意的是: 非key分区的流, 即使把并行度设置为大于1 的数, 窗口也只能在某个分区上使用

Flink(八)【Flink的窗口机制】的更多相关文章

  1. Flink Window窗口机制

    总览 Window 是flink处理无限流的核心,Windows将流拆分为有限大小的"桶",我们可以在其上应用计算. Flink 认为 Batch 是 Streaming 的一个特 ...

  2. 总结Flink状态管理和容错机制

    本文来自8月11日在北京举行的 Flink Meetup会议,分享来自于施晓罡,目前在阿里大数据团队部从事Blink方面的研发,现在主要负责Blink状态管理和容错相关技术的研发.   本文主要内容如 ...

  3. Flink状态管理和容错机制介绍

    本文主要内容如下: 有状态的流数据处理: Flink中的状态接口: 状态管理和容错机制实现: 阿里相关工作介绍: 一.有状态的流数据处理# 1.1.什么是有状态的计算# 计算任务的结果不仅仅依赖于输入 ...

  4. 《从0到1学习Flink》—— Flink 中几种 Time 详解

    前言 Flink 在流程序中支持不同的 Time 概念,就比如有 Processing Time.Event Time 和 Ingestion Time. 下面我们一起来看看这几个 Time: Pro ...

  5. 《从0到1学习Flink》—— Flink 写入数据到 ElasticSearch

    前言 前面 FLink 的文章中我们已经介绍了说 Flink 已经有很多自带的 Connector. 1.<从0到1学习Flink>-- Data Source 介绍 2.<从0到1 ...

  6. 《从0到1学习Flink》—— Flink Data transformation(转换)

    前言 在第一篇介绍 Flink 的文章 <<从0到1学习Flink>-- Apache Flink 介绍> 中就说过 Flink 程序的结构 Flink 应用程序结构就是如上图 ...

  7. Android窗口机制分析与UI管理系统

    类图关系 在看Android的窗口机制之前,先看看其主要的类图关系以及层级之间的依赖与调用关系 1.window在当前的android系统的中的呈现形式是PhoneWindow (frameworks ...

  8. TCP的滑动窗口机制【转】

    原文链接:http://www.cnblogs.com/luoquan/p/4886345.html      TCP这个协议是网络中使用的比较广泛,他是一个面向连接的可靠的传输协议.既然是一个可靠的 ...

  9. 【Android】窗口机制分析与UI管理系统

    类图关系 在看Android的窗口机制之前,先看看其主要的类图关系以及层级之间的依赖与调用关系 1.window在当前的android系统的中的呈现形式是PhoneWindow (frameworks ...

随机推荐

  1. docker创建本地主机实例Virtualbox 驱动出错

    宿主机系统:Centos7 64位 创建主机实例Virtualbox 命令:docker-machine create -d virtualbox test 连接centos工具:Finalshell ...

  2. 算法学习->求解三角形最小路径

    00 问题 00-1 描述 对给定高度为n的一个整数三角形,找出从顶部到底部的最小路径和.每个整数只能向下移动到与之相邻的整数. 找到一个一样的力扣题:120. 三角形最小路径和 - 力扣(LeetC ...

  3. Web实时通信,SignalR真香,不用愁了

    前言 对于B/S模式的项目,基础的场景都是客户端发起请求,服务端返回响应结果就结束了一次连接:但在很多实际应用场景中,这种简单的请求和响应模式就显得很吃力,比如消息通知.监控看板信息自动刷新等实时通信 ...

  4. MarkdownPad2弹窗显示HTML Rendering Error(HTML 渲染错误)的解决办法

    MarkdownPad2弹窗显示HTML Rendering Error(HTML 渲染错误)的解决办法 我在打开.md文件的时候,出现以下错误: 解决方式:下载Awesomium SDK并安装,重启 ...

  5. LeetCode刷题 树专题

    树专题 关于树的几个基本概念 1 树的节点定义 2 关于二叉树的遍历方法 2.1 前序遍历 2.2 中序遍历 2.3 后序遍历 2.4 层序遍历 3 几种常见的树介绍 3.1 完全二叉树 3.2 二叉 ...

  6. FZU ICPC 2020 寒假训练 4 —— 模拟(二)

    P1056 排座椅 题目描述 上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情.不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的 D 对同 ...

  7. 美妙绝伦面向node引用-zico图标(逐浪矢量全真图标)1.9发布

    15年前,那个农村小伙初入广告行业被讥笑没有审美 于是他狠下决心,积极研发,缔就技术之核, 再后来,那些PPT和美工er们随便怎么自好,无法让其心怵. 因为他是中华人民共和国唯一具备web.cms.o ...

  8. ES6—数值(Number,Math对象)(复习+学习)

    ES6-数值(Number,Math对象)(复习+学习) 每天一学,今天要学习ES6的关于数的扩展以及复习,然后通过看书,查阅资料,以及webAPI来搞清楚遇到的,没见过的对象方法等等,下面为本次学习 ...

  9. Python 函数 参数传递

    参数传递    在 python 中,类型属于对象,变量是没有类型的:        a=[1,2,3]        a="Runoob"    以上代码中,[1,2,3] 是 ...

  10. Python 字符串索引、切片、修改

    字符串索引.切片.修改1.字符串操作(切片.修改)应用场景    a.爬虫截取网址数据    b.数据分析,语言处理(分词)    c.电信号码升级           0452 8869504   ...