Flink窗口机制

1.窗口的概念

在这里插入图片描述

时间是为窗口服务的。窗口是什么?为什么会有窗口呢?
(1)Flink要处理的数据,一般是从Kafka过来的流式数据,如果只是单纯地统计流的数据量,是没办法统计的。
(2)所以,要人为的 加上了一个时间区间限制(窗口),才可以进行统计。

2.窗口的分类

2.1滚动窗口(tumble)

2.1.1 sql版

窗口大小 = 滑动距离。
它的窗口是紧密排布的,中间没有任何的数据重复和丢失。
在这里插入图片描述

--创建表
CREATE TABLE source_table ( user_id STRING, price BIGINT,`timestamp` bigint,row_time AS TO_TIMESTAMP(FROM_UNIXTIME(`timestamp`)),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = 'node1',        'port' = '9999','format' = 'csv'
);--语法
tumble(row_time,时间间隔),比如,如下的sql
tumble(row_time,interval '5' second),每隔5秒滚动一次。--业务查询逻辑(传统方式)
select 
user_id,
count(*) as pv,
sum(price) as sum_price,
UNIX_TIMESTAMP(CAST(tumble_start(row_time, interval '5' second) AS STRING)) * 1000  as window_start,
UNIX_TIMESTAMP(CAST(tumble_end(row_time, interval '5' second) AS STRING)) * 1000  as window_end
from source_table
group byuser_id,tumble(row_time, interval '5' second);--TVF写法
--语法,跟3个参数:
--参数1:表名
--参数2:表中事件时间列
--参数3:窗口大小
from table(tumble(table source,descriptor(row_time),interval '5' second))
--sql为:
SELECT user_id,UNIX_TIMESTAMP(CAST(window_start AS STRING)) * 1000 as window_start,UNIX_TIMESTAMP(CAST(window_end AS STRING)) * 1000 as window_end,sum(price) as sum_price
FROM TABLE(TUMBLE(TABLE source_table, DESCRIPTOR(row_time), INTERVAL '5' SECOND))
GROUP BY window_start, window_end,user_id;
--window_start,window_end是新写法的关键字

在这里插入图片描述

在事件时间下,窗口的划分是根据第一条事件时间来划分的,只有等数据来了才会创建窗口。计算公式 = 事件时间   - (事件时间 % 窗口大小)
刚刚的案例中,第一条数据的事件时间为1,窗口大小为5
1 - (1 % 5) = 0,所以,窗口的起始是从0开始。
由于窗口的大小是5秒,因此,后面的窗口排布就是:
[0,5)
[5,10)
[10,15)什么时候触发计算呢?
在事件时间下,窗口的触发计算就是窗口结束 - 1(毫秒)。比如上面的窗口是[0,5),结束的点就是5 * 1000 - 1 = 4999。所以,我们输入5秒的时候,会触发窗口内的数据计算。

2.1.2 DataStream API版

开发步骤:
//1.创建流式执行环境
//2.数据源
//3.数据处理//3.1数据map转换操作,转成Tuple3//3.2把Tuple3的数据添加Watermark(monotonousTimestamps)前两个目的是为了指定时间列(才能根据这一列进行窗口的划分)//3.3把数据根据id进行分组//3.4分组之后,设置滚动事件时间窗口,并且制定窗口大小为5秒钟//3.5对窗口内的数据进行sum操作//3.6把Tuple3转成了Tuple2(取id和sum的值)
//4.数据输出
//5.启动流式任务
package flink.test;import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;public class tests {public static void main(String[] args) throws Exception {// TODO:  1.创建流式执行环境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);// TODO: 2.数据源DataStreamSource<String> source = env.socketTextStream("node1", 9999);// TODO: 3.处理数据//分配窗口,创建窗口就有水位线,不需要就设置为0,类似于sql版/*** WatermarkStrategy的策略有四种:* forMonotonousTimestamps,单调递增水印* forBoundedOutOfOrderness,允许乱序数据(数据迟到)的水印* forGenerator,自定义水印* noWatermarks,没有水印** ---* (1)map转换得到 每一行对应的列* (2)通过 .assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple3<String, Integer, Long>>forMonotonousTimestamps() 来创建窗口* (3) .withTimestampAssigner() 来指定哪一列来表示时间列(才能根据这一列进行窗口的划分)*/SingleOutputStreamOperator<Tuple3<String, Integer, Long>> mapAndWatermarkStream = source.map(new MapFunction<String, Tuple3<String, Integer, Long>>() {@Overridepublic Tuple3<String, Integer, Long> map(String s) throws Exception {String[] lines = s.split(",");/*** lines分为3个字段:String id,Integer price,Long ts 所有要类型转换一下*/return Tuple3.of(lines[0], Integer.valueOf(lines[1]), Long.valueOf(lines[2]));}}).assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple3<String, Integer, Long>>forMonotonousTimestamps().withTimestampAssigner(new SerializableTimestampAssigner<Tuple3<String, Integer, Long>>() {@Overridepublic long extractTimestamp(Tuple3<String, Integer, Long> element, long l) {//这个方法用于标记 哪一列是表示时间戳return element.f2 * 1000L;}}));mapAndWatermarkStream.print("原数据:");//数据分组 sql group byKeyedStream<Tuple3<String, Integer, Long>, String> keybyStream = mapAndWatermarkStream.keyBy(value -> value.f0);//划分窗口和统计  指定窗口的大小,再sum  ---》类似与离线 sql  where条件限制范围 time between  20240101 and 20240107(比如说求一周内的某个指标) 和 select中的 sumSingleOutputStreamOperator<Tuple3<String, Integer, Long>> result = keybyStream.window(TumblingEventTimeWindows.of(Time.seconds(5))).sum(1).returns(Types.TUPLE(Types.STRING, Types.INT));// TODO: 4.数据输出result.printToErr("聚合后的数据:");// TODO: 5.启动流式任务env.execute();}
}

数据输出和结果输出:
在这里插入图片描述
在这里插入图片描述

2.2滑动窗口(hop)

滑动窗口 :滑动距离 不等于 窗口大小。

(1)如果滑动距离<窗口大小===>数据重复;

(2)如果滑动距离=窗口大小===>滚动窗口(没有任何的数据重复和丢失);

(3)如果滑动距离>窗口大小===>数据丢失(不考虑)!!!
在这里插入图片描述

2.2.1 sql版

--创建表
CREATE TABLE source_table ( user_id STRING, price BIGINT,`timestamp` bigint,row_time AS TO_TIMESTAMP(FROM_UNIXTIME(`timestamp`)),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = 'node1',        'port' = '9999','format' = 'csv'
);--语法
hop(事件时间列,滑动间隔,窗口大小)
hop(row_time,interval '2' second, interval '5' second)--业务SQL
SELECT user_id,
UNIX_TIMESTAMP(CAST(hop_start(row_time, interval '2' SECOND, interval '5' SECOND) AS STRING)) * 1000 as window_start,
UNIX_TIMESTAMP(CAST(hop_end(row_time, interval '2' SECOND, interval '5' SECOND) AS STRING)) * 1000 as window_end, sum(price) as sum_price
FROM source_table
GROUP BY user_id, hop(row_time, interval '2' SECOND, interval '5' SECOND);--每隔两秒滑动一次--TVF写法
--table:表名
--descriptor:事件时间列
--滑动距离:interval 2 second
--窗口大小:interval 5 second
from table(hop(table 表名,descriptor(事件时间列),滑动间隔,窗口大小))
from table(hop(table source,descriptor(row_time),interval '2' second,interval '5' second))--sql为:
SELECT user_id,
UNIX_TIMESTAMP(CAST(window_start AS STRING)) * 1000 as window_start,  
UNIX_TIMESTAMP(CAST(window_end AS STRING)) * 1000 as window_end, sum(price) as sum_price
FROM TABLE(HOP(TABLE source_table, DESCRIPTOR(row_time), interval '2' SECOND, interval '6' SECOND))
GROUP BY window_start, window_end,user_id;

数据输入和运行结果如下:

在这里插入图片描述

在这里插入图片描述
说明:

(1)事件时间1的到来,会让窗口仅限排布(划分),划分的窗口如下:

[-2,3],[0,5],[2,7],[4,9]

(2)窗口每隔两秒滑动一次,所以会有数据重复计算。

2.2.2 DataStream API版

package flink.test;import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;public class Demo02_SlideWindow {public static void main(String[] args) throws Exception {//1.创建流式执行环境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);//2.数据源DataStreamSource<String> source = env.socketTextStream("node1", 9999);//3.数据处理//3.1数据map转换操作,转成Tuple3SingleOutputStreamOperator<Tuple3<String, Integer, Long>> mapStream = source.map(value -> {/*** 由一行数据中,用逗号进行切分【id,price,ts】* String id* Integer price* Long ts*/String[] lines = value.split(",");return Tuple3.of(lines[0], Integer.valueOf(lines[1]), Long.parseLong(lines[2]));}).returns(Types.TUPLE(Types.STRING, Types.INT, Types.LONG));//3.2把Tuple3的数据添加Watermark(monotonousTimestamps)/*** WatermarkStrategy生成水印的策略有四种:* forMonotonousTimestamps,单调递增水印(用的次多)* forBoundedOutOfOrderness,运行数据迟到(乱序)(用的最多)* forGeneric,自定义水印(不用)* noWatermark,没有水印(不用)*/SingleOutputStreamOperator<Tuple3<String, Integer, Long>> watermarks = mapStream.assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple3<String, Integer, Long>>forMonotonousTimestamps().withTimestampAssigner(new SerializableTimestampAssigner<Tuple3<String, Integer, Long>>() {@Overridepublic long extractTimestamp(Tuple3<String, Integer, Long> element, long recordTimestamp) {return element.f2 * 1000L;}}));//3.3把数据根据id进行分组watermarks.print("源数据:");SingleOutputStreamOperator<Tuple3<String, Integer, Long>> sumStream = watermarks.keyBy(value -> value.f0)//3.4分组之后,设置滑动事件时间窗口,并且制定窗口大小为5秒钟,滑动间隔为2秒。/*** SlidingEventTimeWindows,滑动事件时间窗口,带2个参数:* 参数1:窗口大小* 参数2:滑动间隔*/.window(SlidingEventTimeWindows.of(Time.seconds(5), Time.seconds(2)))//3.5对窗口内的数据进行sum操作.sum(1);//3.6把Tuple3转成了Tuple2(取id和sum的值)SingleOutputStreamOperator<Tuple2<String, Integer>> result = sumStream.map(value -> Tuple2.of(value.f0, value.f1)).returns(Types.TUPLE(Types.STRING,Types.INT));//4.数据输出result.printToErr("聚合后的数据:");//5.启动流式任务env.execute();}
}

数据输入和结果输出:
在这里插入图片描述
在这里插入图片描述

2.3会话窗口(session)

会话窗口:在一个会话周期内,窗口的数据会累积,超过会话周期就会触发窗口的计算,同时开辟下一个新窗口。
注意:

数据本身的事件时间大于窗口间隔,才会触发当前窗口的计算。
在这里插入图片描述

2.3.1 sql版

--创建表
CREATE TABLE source_table ( user_id STRING, price BIGINT,`timestamp` bigint,row_time AS TO_TIMESTAMP(FROM_UNIXTIME(`timestamp`)),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = 'node1',        'port' = '9999','format' = 'csv'
);--语法
session(事件时间列,窗口间隔)
session(row_time,interval '5' second)--业务SQL
SELECT user_id,
UNIX_TIMESTAMP(CAST(session_start(row_time, interval '5' SECOND) AS STRING)) * 1000 as window_start,
UNIX_TIMESTAMP(CAST(session_end(row_time, interval '5' SECOND) AS STRING)) * 1000 as window_end, sum(price) as sum_price
FROM source_table
GROUP BY user_id, session(row_time, interval '5' SECOND);!!!会话窗口没有TVF写法。

数据输入和结果输出:
在这里插入图片描述

在这里插入图片描述

2.3.2 DataStream API版

package flink.test;import org.apache.flink.api.common.eventtime.SerializableTimestampAssigner;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.tuple.Tuple3;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.EventTimeSessionWindows;
import org.apache.flink.streaming.api.windowing.time.Time;public class Demo03_SessionWindow {public static void main(String[] args) throws Exception {//1.创建流式执行环境StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);//2.数据源DataStreamSource<String> source = env.socketTextStream("node1", 9999);//3.数据处理//3.1数据map转换操作,转成Tuple3SingleOutputStreamOperator<Tuple3<String, Integer, Long>> mapStream = source.map(new MapFunction<String, Tuple3<String, Integer, Long>>() {@Overridepublic Tuple3<String, Integer, Long> map(String value) throws Exception {/*** String id* Integer price* Long ts*/String[] lines = value.split(",");return Tuple3.of(lines[0], Integer.valueOf(lines[1]), Long.parseLong(lines[2]));}});//3.2把Tuple3的数据添加Watermark(monotonousTimestamps)SingleOutputStreamOperator<Tuple3<String, Integer, Long>> watermarks = mapStream.assignTimestampsAndWatermarks(WatermarkStrategy.<Tuple3<String, Integer, Long>>forMonotonousTimestamps().withTimestampAssigner(new SerializableTimestampAssigner<Tuple3<String, Integer, Long>>() {@Overridepublic long extractTimestamp(Tuple3<String, Integer, Long> element, long recordTimestamp) {return element.f2 * 1000L;}}));watermarks.print("源数据:");//3.3把数据根据id进行分组//3.4分组之后,设置会话事件时间窗口,并且指定窗口间隔为5秒钟。//3.5对窗口内的数据进行sum操作SingleOutputStreamOperator<Tuple3<String, Integer, Long>> sumStream = watermarks.keyBy(value -> value.f0).window(EventTimeSessionWindows.withGap(Time.seconds(5))).sum(1);//3.6把Tuple3转成了Tuple2(取id和sum的值)SingleOutputStreamOperator<Tuple2<String, Integer>> result = sumStream.map(value -> Tuple2.of(value.f0, value.f1)).returns(Types.TUPLE(Types.STRING, Types.INT));//4.数据输出result.printToErr("聚合后的结果:");//5.启动流式任务env.execute();}
}

数据输入和结果输出:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/1502.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言程序设计:简易版的printf函数实现

简易版的printf函数实现 功能说明 &#xff08;1&#xff09;使用putchar函数、va可变参完成printf函数基本功能的实现&#xff1b; &#xff08;2&#xff09;函数说明&#xff1a; 实现对下列数据类型的输出&#xff0c;并返回成功输出打印的字符个数&#xff1a; 整数&…

在CSDN创作了6个月,我收获了什么?文末送书~

作者主页&#xff1a;阿玥的小东东主页&#xff01; 正在学习&#xff1a;python和C/C 期待大家的关注哦 目录 一次很好的机会&#xff0c;让我开始了CSDN之旅 首先来看看我的几位领路人 创作动力 1W粉丝 在CSDN我收获了什么&#xff1f; 很高的展现量 认证创作者身份 社…

【Linux】系统安全及应用

目录 一、账号安全基本措施 1.系统账号清理 2.密码安全控制 3.历史命令安全管理 4.限制su切换用户 1&#xff09;将信任的用户加入到wheel组中 2&#xff09;修改su的PAM认证配置文件 5.ssh远程登录输入三次密码错误则锁定用户 二、Linux中的PAM安全认证 1.su命令的…

Redis入门到通关之数据结构解析-动态字符串SDS

文章目录 Redis数据结构-动态字符串动态扩容举例二进制安全SDS优点与C语言中的字符串的区别 Redis数据结构-动态字符串 我们都知道 Redis 中保存的Key是字符串&#xff0c;value 往往是字符串或者字符串的集合。可见字符串是 Redis 中最常用的一种数据结构。 不过 Redis 没有…

Android Studio超级详细讲解下载、安装配置教程(建议收藏)

博主介绍&#xff1a;✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神&#xff0c;答疑解惑、坚持优质作品共享。本人是掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战&#xff0c;深受全网粉丝喜爱与支持✌有…

贪吃蛇游戏实现(VS编译环境)

贪吃蛇游戏 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;C语言&#x1f353; &#x1f33c;文章目录&#x1f33c; 0. 前言 1. 游戏背景 2. 实现后游戏画面展示 3. 技术要求 4. Win32 API介绍 4.1 Win32 API 4.2 控制台程序 4.…

Java之类和对象

一面向对象的初步认知 1.什么是面向对象 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情。用面向对象的思想…

嵌入式物联网实战开发笔记-乐鑫ESP32开发环境ESP-IDF搭建【doc.yotill.com】

乐鑫ESP32入门到精通项目开发参考百例下载&#xff1a; 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;4e33 3.1 ESP-IDF 简介 ESP-IDF&#xff08;Espressif IoT Development Framework&#xff09;是乐鑫&#xff08;Espressif Systems&#xff09;为 ESP 系列…

大型网站系统架构演化实例_2.使用缓存改善网站性能

1.使用缓存改善网站性能 网站访问的特点和现实世界的财富分配一样遵循二八定律&#xff1a;80%的业务访问集中在20%的数据上。既然大部分业务访问集中在一小部分数据上&#xff0c;那么如果把这一小部分数据缓存在内存中&#xff0c;就可以减少数据库的访问压力&#xf…

【Python】自定义修改pip下载模块默认的安装路径

因为电脑下载了Anaconda提供的默认Python 3.9 以及后期下载的python3.10所以在Pychram进行项目开发时&#xff0c;发现一些库怎么导入都导入不了&#xff0c;手动install也是失败&#xff0c;后期在cmd里面发现python以及pip配置有点儿混乱&#xff0c;导致执行命令时&#xff…

碳循环、人类、遥感之间的关联

1. 碳与碳循环 碳是自然界中很常见的一种元素&#xff0c;它以多种形式广泛存在于大气和地壳之中。碳单质很早就被人认识和利用&#xff0c;碳的一系列化合物——有机物是生命的根本。 1.1 自然界中的碳 地球上最大的两个碳库是岩石圈和化石燃料&#xff0c;含碳量约占…

在RISC-V64架构的CV1811C开发板上应用perf工具进行多线程程序性能分析及火焰图调试

CV1811C环境编译 SDK目录结构 . ├── build // 编译目录,存放编译脚本以及各board差异化配置 ├── buildroot-2021.05 // buildroot开源工具 ├── freertos // freertos系统 ├── fsbl // fsbl启动固件,prebuilt形式存在…

Android14 - WindowManagerService之客户端Activity布局

Android14 - WindowManagerService之客户端Activity布局 一、主要角色 WMS作为一个服务端&#xff0c;有多种客户端与其交互的场景。我们以常见的Activity为例&#xff1a; Activity&#xff1a;在ActivityThread构建一个Activity后&#xff0c;会调用其attach方法&#xff0c;…

[docker] volume 补充 环境变量 参数

[docker] volume 补充 & 环境变量 & 参数 这里补充一下 volume 剩下的内容&#xff0c;以及添加参数(ARG) 和 环境变量 ENV 的内容 read only volumes ❯ docker run-p 3000:80--rm--name feedback-app-v feedback:/app/feedback-v "$(pwd):/app"-v /app/…

【C++初阶】vector使用特性 vector模拟实现

1.vector的介绍及其使用 1.1 vector的介绍 vector文档介绍 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#…

第24天:安全开发-PHP应用文件管理模块显示上传黑白名单类型过滤访问控制

第二十四天 一、PHP文件管理-显示&上传功能实现 如果被抓包抓到数据包&#xff0c;并修改Content-Type内容 则也可以绕过筛查 正常进行上传和下载 二、文件上传-$_FILES&过滤机制实现 无过滤机制 黑名单过滤机制 使用 explode 函数通过点号分割文件名&#xff0c;…

VTC视频时序控制器原理以及Verilog实现

文章目录 一、前言二、视频时序控制原理三、Verilog实现3.1 代码3.2 仿真以及分析 一、前言 VTC&#xff08;Video Timing Controller&#xff09;是一种用于产生视频时序的控制器&#xff0c;在FPGA图像领域经常用到。Xilinx Vivado 也有专门用于生成视频时序的 IP&#xff0c…

webpack-babel2

浏览器的兼容性问题 浏览器的兼容性问题不知包括随屏幕大小而变化&#xff0c;还包括针对浏览器支持的特性&#xff08;如css特性&#xff0c;js特性&#xff09; 做处理。 目前市场上有很多浏览器&#xff1a;Chrome,Safari,IE,Edge等&#xff0c;要根据它们的市场占有率来决…

vue 对axios二次封装,配置api层,基于mock测试数据

一、初始化环境&#xff08;默认都会安装vue3项目ts&#xff09; 安装mock&#xff1a;全局安装 # 使用 npm 安装 npm install mockjs vite-plugin-mock # 使用 yarn 安装 yarn add mockjs vite-plugin-mock 二、进行配置 在vite.config.ts中进行配置 import { UserConfigEx…