大数据Flink(一百一十七):Flink SQL的窗口操作
文章目录
Flink SQL的窗口操作
一、窗口的概述
二、Group Windows
1、滚动窗口(TUMBLE)
2、滑动窗口(HOP)
3、Session 窗口(SESSION)
4、渐进式窗口(CUMULATE)
三、Over Windows
1、时间区间聚合(RANGE OVER Window)
2、行数聚合
Flink SQL的窗口操作
一、窗口的概述
在流处理应用中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理。当然我们可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处理,例如:在过去的1分钟内有多少用户点击了我们的网页。在这种情况下,我们必须定义一个窗口,用来收集最近一分钟内的数据,并对这个窗口内的数据进行计算。
Flink 认为 Batch 是 Streaming 的一个特例,所以 Flink 底层引擎是一个流式引擎,在上面实现了流处理和批处理。而窗口(window)就是从 Streaming 到 Batch 的一个桥梁。
- 一个Window代表有限对象的集合。一个窗口有一个最大的时间戳,该时间戳意味着在其代表的某时间点——所有应该进入这个窗口的元素都已经到达。
- Window就是用来对一个无限的流设置一个有限的集合,在有界的数据集上进行操作的一种机制。
- 在Table API和SQL中,主要有两种窗口:Group Windows 和 Over Windows。
- Group Windows 根据时间或行计数间隔将组行聚合成有限的组,并对每个组计算一次聚合函数
- Over Windows 窗口内聚合为每个输入行在其相邻行范围内计算一个聚合
二、Group Windows
1、滚动窗口(TUMBLE)
滚动窗口定义:滚动窗口将每个元素指定给指定窗口大小的窗口。滚动窗口具有固定大小,且不重叠。例如,指定一个大小为 5 分钟的滚动窗口。在这种情况下,Flink 将每隔 5 分钟开启一个新的窗口,其中每一条数都会划分到唯一一个 5 分钟的窗口中,如下图所示。
TUMBLE函数基于时间属性字段为关系的每一行指定一个窗口。
在流模式下,时间属性字段必须是事件或处理时间属性。
在批处理模式下,窗口表函数的时间属性字段必须是TIMESTAMP或TIMESTAMP _LTZ类型的属性。TUMBLE的返回值是一个新的关系,它包括原始关系的所有列,以及另外3列“window_start”、“window_end”、“window_time”,以指示指定的窗口。原始时间属性“timecol”将是窗口TVF之后的常规时间戳列。
TUMBLE函数接受三个必需参数,一个可选参数:
TUMBLE(TABLE data, DESCRIPTOR(timecol), size [, offset ])
- data: 是一个表参数,可以是与时间属性列的任何关系。
- timecol: 是一个列描述符,指示数据的哪些时间属性列应映射到翻转窗口。
- size: 是指定滚动窗口宽度的持续时间。
- offset: 是一个可选参数,用于指定窗口起始位置的偏移量。
应用场景:常见的按照一分钟对数据进行聚合,计算一分钟内 PV,UV 数据。
实际案例:简单且常见的分维度分钟级别同时在线用户数、总销售额
那么上面这个案例的 SQL 要咋写呢?
关于滚动窗口,在 1.14 版本之前和 1.14 及之后版本有两种 Flink SQL 实现方式,分别是:
- Group Window Aggregation(1.14 之前只有此类方案,此方案在 1.14 及之后版本已经标记为废弃,不推荐使用)
- Windowing TVF(1.14 及之后建议使用 Windowing TVF)
这里两种方法都会介绍:
- Group Window Aggregation 方案(支持 Batch\Streaming 任务):
使用socket演示:
监听9999端口:nc -lk 9999
测试数据如下(创建完表,启动查询任务后,再进行输入)
1,12189,80729,2021-05-23 05:16:39
1,78750,7434,2021-05-23 05:16:41
1,38905,75583,2021-05-23 05:16:42
1,29388,52138,2021-05-23 05:16:45
1,51810,84241,2021-05-23 05:16:47
1,34713,87372,2021-05-23 05:16:48
1,62264,61675,2021-05-23 05:16:52
1,32460,29190,2021-05-23 05:17:40
1,73052,15170,2021-05-23 05:23:00
进入阿里云Flink开发平台创建表,首先使用处理时间进行演示(代码如下)
CREATE TABLE tumble_group_proctime ( dim STRING, user_id BIGINT, price BIGINT,`timestamp` STRING,row_time AS TO_TIMESTAMP(`timestamp`),pt AS PROCTIME()
) WITH ('connector' = 'socket','hostname' = '128.66.209.119', 'port' = '9999','format' = 'csv'
);
查询语句如下,可以看到 Group Window Aggregation 滚动窗口的 SQL 语法就是把 tumble window 的声明写在了 group by 子句中,即 tumble(pt, interval '5' second)。第一个参数为处理时间,第二个参数为滚动窗口大小。
如果使用窗口开始时间或者结束的话,语法如下:tumble_start(pt, interval '5' second)、tumble_end(pt, interval '5' second)。
select --窗口开始时间tumble_start(pt, interval '5' second) as window_start,--窗口结束时间tumble_end(pt, interval '5' second) as window_end,dim,count(*) as pv,sum(price) as sum_price,max(price) as max_price,min(price) as min_price,-- 计算 uv 数count(distinct user_id) as uv
from tumble_group_proctime
group by
dim,tumble(pt, interval '5' second);
选中查询代码,点击调试,查看结果。目前没有传入数据,所以没有结果。
下面开始通过socket传入测试数据。首先传入第一条数据,在几秒后,可以看到一条结果。
同时传入剩下的数据,可以看到另一条结果
第一个条结果的pv为1,即只有一条数据。这里因为在这个5秒的窗口时间内,只有第一条数据。第二个结果的pv为8,即有八条数据。显然,在这个5秒的时间窗口内,有八条数据。这条结果是八条数据聚合的结果。
接下来使用事件时间进行演示(代码如下)
--事件时间演示
CREATE TABLE tumble_group_eventime ( dim STRING, user_id BIGINT, price BIGINT,`timestamp` STRING,row_time AS TO_TIMESTAMP(`timestamp`),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = '128.66.209.119', 'port' = '9999','format' = 'csv'
);
查询语句如下
select --窗口开始时间tumble_start(row_time, interval '5' second) as window_start,--窗口结束时间tumble_end(row_time, interval '5' second) as window_end,dim,count(*) as pv,sum(price) as sum_price,max(price) as max_price,min(price) as min_price,-- 计算 uv 数count(distinct user_id) as uv
from tumble_group_eventime
group bydim,tumble(row_time, interval '5' second);
选中查询代码,点击调试,查看结果。目前没有传入数据,所以没有结果。
下面开始通过socket传入测试数据。首先传入第一条数据,发现无论等待多久,都没有结果产生。
这是因为第一条数据输入后,创建了一个时间窗口。但是没有输入第二条数据,即没有出现数据的事件时间大于窗口的结束时间,所以这个窗口不会结束,因此就不会触发计算,也就看不到结果。
输入第二条数据,发现看到了结果
观察测试数据可以看到,第一条数据的事件时间为2021-05-23 05:16:39,处于上面结果的窗口时间内。第二条数据的事件时间为2021-05-23 05:16:41,大于上面结果的窗口的结束时间,因而触发了这个窗口的计算。
输入剩下的数据,可以看到结果。
可以对比数据分析结果,这里不再赘述。
- Window TVF 方案(1.14 只支持 Streaming 任务,1.15版本开始支持 Batch\Streaming 任务):
建表语句
-- TVF
CREATE TABLE tumble_tvf ( dim STRING, user_id BIGINT, price BIGINT,`timestamp` STRING,row_time AS TO_TIMESTAMP(`timestamp`),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = '179.18.59.99', 'port' = '9999','format' = 'csv'
);
查询语句
SELECT dim,window_start,window_end,count(*) as pv,sum(price) as sum_price,max(price) as max_price,min(price) as min_price,count(distinct user_id) as uv
FROM TABLE(TUMBLE(TABLE tumble_tvf, DESCRIPTOR(row_time), INTERVAL '5' SECOND))
GROUP BY window_start, window_end,dim;
可以看到 Windowing TVF 滚动窗口的写法就是把 tumble window 的声明写在了数据源的 Table 子句中,即 TABLE(TUMBLE(TABLE source_table, DESCRIPTOR(row_time), INTERVAL '5' SECOND)),包含三部分参数。
第一个参数 TABLE source_table 声明数据源表;第二个参数 DESCRIPTOR(row_time) 声明数据源的时间戳;第三个参数 INTERVAL '5' SECOND 声明滚动窗口大小为 5 秒。
返回值除了输入的参数外,还有window_start, window_end,window_time。window_start返回窗口的起始时间(包含边界),window_end返回窗口的结束时间(包含边界),window_time返回窗口的结束时间(不包含边界)。window_time等于window_end减去1ms。
- 注意事项
事件时间中滚动窗口的窗口计算触发是由 Watermark 推动的。 |
2、滑动窗口(HOP)
滑动窗口定义:滑动窗口也是将元素指定给固定长度的窗口。与滚动窗口功能一样,也有窗口大小的概念。不一样的地方在于,滑动窗口有另一个参数控制窗口计算的频率(滑动窗口滑动的步长)。因此,如果滑动的步长小于窗口大小,则滑动窗口之间每个窗口是可以重叠。在这种情况下,一条数据就会分配到多个窗口当中。举例,有 10 分钟大小的窗口,滑动步长为 5 分钟。这样,每 5 分钟会划分一次窗口,这个窗口包含的数据是过去 10 分钟内的数据,如下图所示。
在流模式下,时间属性字段必须是事件或处理时间属性。
在批处理模式下,窗口表函数的时间属性字段必须是TIMESTAMP或TIMESTAMP _LTZ类型的属性。TUMBLE的返回值是一个新的关系,它包括原始关系的所有列,以及另外3列“window_start”、“window_end”、“window_time”,以指示指定的窗口。原始时间属性“timecol”将是窗口TVF之后的常规时间戳列。
HOP接受四个必需参数,一个可选参数:
HOP(TABLE data, DESCRIPTOR(timecol), slide, size [, offset ])
- data: 是一个表参数,可以是与时间属性列的任何关系。
- timecol:是一个列描述符,指示数据的哪些时间属性列应映射到跳跃窗口。
- slide: 是一个持续时间,指定顺序跳跃窗口开始之间的持续时间
- size: 是指定跳跃窗口宽度的持续时间。
- offset: 是一个可选参数,用于指定窗口起始位置的偏移量。
应用场景:比如计算同时在线的数据,要求结果的输出频率是 1 分钟一次,每次计算的数据是过去 5 分钟的数据(有的场景下用户可能在线,但是可能会 2 分钟不活跃,但是这也要算在同时在线数据中,所以取最近 5 分钟的数据就能计算进去了)
实际案例:简单且常见的分维度分钟级别同时在线用户数,2 秒钟输出一次,计算最近 6 秒钟的数据
依然是 Group Window Aggregation、Windowing TVF 两种方案:
- Group Window Aggregation 方案(支持 Batch\Streaming 任务):
CREATE TABLE hop_group ( dim STRING, user_id BIGINT, price BIGINT,`timestamp` STRING,row_time AS TO_TIMESTAMP(`timestamp`),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = '178.23.141.244', 'port' = '9999','format' = 'csv'
);SELECT hop_start(row_time, interval '2' SECOND, interval '6' SECOND) as window_start,hop_end(row_time, interval '2' SECOND, interval '6' SECOND) as window_end, dim,count(distinct user_id) as uv
FROM hop_group
GROUP BY dim, hop(row_time, interval '2' SECOND, interval '6' SECOND);
可以看到 Group Window Aggregation 滚动窗口的写法就是把 hop window 的声明写在了 group by 子句中,即 hop(row_time, interval '2' SECOND, interval '6' SECOND)。其中:
第一个参数为事件时间的时间戳;
第二个参数为滑动窗口的滑动步长;
第三个参数为滑动窗口大小。
查询结果
- Windowing TVF 方案(1.14 只支持 Streaming 任务,1.15版本开始支持 Batch\Streaming 任务):
CREATE TABLE hop_tvf ( dim STRING, user_id BIGINT, price BIGINT,`timestamp` STRING,row_time AS TO_TIMESTAMP(`timestamp`),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = '178.23.141.244', 'port' = '9999','format' = 'csv'
);SELECT dim,window_start, window_end, count(distinct user_id) as uv
FROM TABLE(HOP(TABLE hop_tvf, DESCRIPTOR(row_time), interval '2' SECOND, interval '6' SECOND))
GROUP BY window_start, window_end,dim;
可以看到 Windowing TVF 滚动窗口的写法就是把 hop window 的声明写在了数据源的 Table 子句中,即 TABLE(HOP(TABLE source_table, DESCRIPTOR(row_time), INTERVAL '2' SECOND, INTERVAL '6' SECOND)),包含四部分参数:
第一个参数 TABLE source_table 声明数据源表;
第二个参数 DESCRIPTOR(row_time) 声明数据源的时间戳;
第三个参数 INTERVAL '2' SECOND 声明滚动窗口滑动步长大小为2 SECOND。
第四个参数 INTERVAL '6' SECOND 声明滚动窗口大小为6 SECOND。
查询结果
3、Session 窗口(SESSION)
Session 窗口定义:Session 时间窗口和滚动、滑动窗口不一样,其没有固定的持续时间,如果在定义的间隔期(Session Gap)内没有新的数据出现,则 Session 就会窗口关闭。如下图对比所示:
应用场景:计算每个用户在活跃期间(一个 Session)总共购买的商品数量,如果用户 5 分钟没有活动则视为 Session 断开
案例
目前 1.15 版本中 Flink SQL 不支持 Session 窗口的 Window TVF,所以这里就只介绍 Group Window Aggregation 方案:
- Group Window Aggregation 方案(支持 Batch\Streaming 任务):
CREATE TABLE session_group ( dim STRING, user_id BIGINT, price BIGINT,`timestamp` STRING,row_time AS TO_TIMESTAMP(`timestamp`),watermark for row_time as row_time - interval '0' second
) WITH ('connector' = 'socket','hostname' = '178.23.148.244', 'port' = '9999','format' = 'csv'
);SELECT session_start(row_time, interval '5' SECOND) as window_start, session_end(row_time, interval '5' SECOND) as window_end, dim,count(1) as pv
FROM session_group
GROUP BY dim, session(row_time, interval '5' SECOND);
- 注意事项
上述 SQL 任务是在整个 Session 窗口结束之后才会把数据输出。Session 窗口即支持 处理时间 也支持 事件时间。但是处理时间只支持在 Streaming 任务中运行,Batch 任务不支持。 Session gap 间隔是5s,实际上是不包含5s,即大于5s才会触发计算 |
可以看到 Group Window Aggregation 中 Session 窗口的写法就是把 session window 的声明写在了 group by 子句中,即 session(row_time, interval '5' SECOND)。其中:
第一个参数为事件时间的时间戳;
第二个参数为 Session gap 间隔。
4、渐进式窗口(CUMULATE)
渐进式窗口定义:渐进式窗口是 固定窗口间隔内提前触发的的滚动窗口,其实就是 Tumble Window + early-fire 的一个事件时间的版本。
例如,从每日零点到当前这一分钟绘制累积 UV,其中 10:00 时的 UV 表示从 00:00 到 10:00 的 UV 总数。
渐进式窗口可以认为是首先开一个最大窗口大小的滚动窗口,然后根据用户设置的触发的时间间隔将这个滚动窗口拆分为多个窗口,这些窗口具有相同的窗口起点和不同的窗口终点。如下图所示:
这些CUMULATE函数根据时间属性列分配窗口。
在流模式下,时间属性字段必须是事件或处理时间属性。
在批处理模式下,窗口表函数的时间属性字段必须是TIMESTAMP或TIMESTAMP _LTZ类型的属性。CUMULATE的返回值是一个新的关系,它包括原始关系的所有列,以及另外3列“window_start”、“window_end”、“window_time”,以指示指定的窗口。原始时间属性“timecol”将是窗口TVF之后的常规时间戳列。
CUMULATE接受四个必需参数,一个可选参数:
CUMULATE(TABLE data, DESCRIPTOR(timecol), step, size)
- data: 是一个表参数,可以是与时间属性列的任何关系。
- timecol:是一个列描述符,指示数据的哪些时间属性列应映射到累积窗口。
- step: 是指定连续累积窗口结束之间增加的窗口大小的持续时间。
- size: 是指定累积窗口的最大宽度的持续时间。size必须是step的整数倍。
- offset: 是一个可选参数,用于指定窗口起始位置的偏移量。
应用场景:周期内累计 PV,UV 指标(如每天累计到当前这一分钟的 PV,UV)。这类指标是一段周期内的累计状态,对分析师来说更具统计分析价值,而且几乎所有的复合指标都是基于此类指标的统计(不然离线为啥都要累计一天的数据,而不要一分钟累计的数据呢)。
实际案例:每天的截止当前分钟的累计 money(sum(money)),去重 id 数(count(distinct id))。每天代表渐进式窗口大小为 1 天,分钟代表渐进式窗口移动步长为分钟级别。举例如下:
明细输入数据:
time | id | money |
2021-11-01 00:01:00 | A | 3 |
2021-11-01 00:01:00 | B | 5 |
2021-11-01 00:01:00 | A | 7 |
2021-11-01 00:02:00 | C | 3 |
2021-11-01 00:03:00 | C | 10 |
预期经过渐进式窗口计算的输出数据:
time | count distinct id | sum money |
2021-11-01 00:01:00 | 2 | 15 |
2021-11-01 00:02:00 | 3 | 18 |
2021-11-01 00:03:00 | 3 | 28 |
转化为折线图长这样:
可以看到,其特点就在于,每一分钟的输出结果都是当天零点累计到当前的结果。
渐进式窗口目前只有 Windowing TVF 方案支持:
- Windowing TVF 方案(1.14 只支持 Streaming 任务,1.15版本开始支持 Batch\Streaming 任务):
-
CREATE TABLE cumulate_tvf (-- 用户 iduser_id BIGINT,-- 金额money BIGINT,-- 事件时间戳row_time AS cast(CURRENT_TIMESTAMP as timestamp(3)),-- watermark 设置WATERMARK FOR row_time AS row_time - INTERVAL '0' SECOND ) WITH ('connector' = 'datagen','rows-per-second' = '10','fields.user_id.min' = '1','fields.user_id.max' = '100000','fields.money.min' = '1','fields.money.max' = '100000' );SELECT window_start, window_end,sum(money) as sum_money,count(distinct user_id) as count_distinct_id FROM TABLE(CUMULATE(TABLE cumulate_tvf, DESCRIPTOR(row_time), INTERVAL '60' SECOND, INTERVAL '1' DAY)) GROUP BYwindow_start, window_end;
一分钟内可以看到有结果输出,之后每分钟增加一条。结果如下
可以看到 Windowing TVF 滚动窗口的写法就是把 cumulate window 的声明写在了数据源的 Table 子句中,即 TABLE(CUMULATE(TABLE source_table, DESCRIPTOR(row_time), INTERVAL '60' SECOND, INTERVAL '1' DAY)),其中包含四部分参数:
第一个参数 TABLE source_table 声明数据源表;
第二个参数 DESCRIPTOR(row_time) 声明数据源的时间戳;
第三个参数 INTERVAL '60' SECOND 声明渐进式窗口触发的渐进步长为 1 min。
第四个参数 INTERVAL '1' DAY 声明整个渐进式窗口的大小为 1 天,到了第二天新开一个窗口重新累计。
三、Over Windows
OVER Window (over聚合)是传统数据库的标准开窗,不同于Group Window,OVER窗口中每1个元素都对应1个窗口。OVER窗口可以按照实际元素的行或实际的元素值(时间戳值)确定窗口,因此流数据元素可能分布在多个窗口中。
在应用OVER窗口的流式数据中,每1个元素都对应1个OVER窗口。每1个元素都触发1次数据计算,每个触发计算的元素所确定的行,都是该元素所在窗口的最后1行。在实时计算的底层实现中,OVER窗口的数据进行全局统一管理(数据只存储1份),逻辑上为每1个元素维护1个OVER窗口,为每1个元素进行窗口计算,完成计算后会清除过期的数据。
拿 over聚合 与 窗口聚合 做一个对比,其之间的直观不同之处在于:
- 窗口聚合:不在 group by 中的字段,不能直接在 select 中拿到
- Over 聚合:能够保留原始字段
Over 聚合的语法总结如下:
SELECTagg1(col1) OVER (definition1) AS colName,...aggN(colN) OVER (definition1) AS colNameN
FROM Tab1;
其中:
- agg1(col1):按照GROUP BY指定col1列对输入数据进行聚合计算。
- OVER (definition1):OVER窗口定义。
- AS colName:别名。
按照计算行的定义方式,OVER Window可以分为以下两类:
RANGE OVER Window:具有相同时间值的所有元素行视为同一计算行,即具有相同时间值的所有行都是同一个窗口。
ROWS OVER Window:每1行元素都被视为新的计算行,即每1行都是一个新的窗口。
1、时间区间聚合(RANGE OVER Window)
- 窗口数据:
RANGE OVER Window所有具有共同元素值(元素时间戳)的元素行确定一个窗口。
- 窗口语法:
SELECTagg1(col1) OVER([PARTITION BY (value_expression1,..., value_expressionN)]ORDER BY timeColRANGE BETWEEN (UNBOUNDED | timeInterval) PRECEDING AND CURRENT ROW) AS colName,
...
FROM Tab1;
- value_expression:进行分区的字表达式。
- timeCol:元素排序的时间字段。
- timeInterval:定义根据当前行开始向前追溯指定时间的元素行。
案例:每条数据对应最近 1 小时的区间,即最新输出的一条数据的 sum 聚合结果就是最近一小时数据的 amount 之和。
CREATE TABLE over_window_time (order_id BIGINT,product BIGINT,amount BIGINT,order_time as cast(CURRENT_TIMESTAMP as TIMESTAMP(3)),WATERMARK FOR order_time AS order_time - INTERVAL '0.001' SECOND
) WITH ('connector' = 'datagen','rows-per-second' = '1','fields.order_id.min' = '1','fields.order_id.max' = '2','fields.amount.min' = '1','fields.amount.max' = '10','fields.product.min' = '1','fields.product.max' = '2'
);SELECT product, order_time, amount,SUM(amount) OVER (PARTITION BY productORDER BY order_time-- 标识统计范围是一个 product 的最近 1 小时的数据RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND CURRENT ROW) AS one_hour_prod_amount_sum
FROM over_window_time;
结果如下:
2、行数聚合
- 窗口数据:
ROWS OVER Window的每个元素都确定一个窗口。
- 窗口语法:
SELECTagg1(col1) OVER([PARTITION BY (value_expression1,..., value_expressionN)]ORDER BY timeColROWS BETWEEN (UNBOUNDED | rowCount) PRECEDING AND CURRENT ROW) AS colName, ...FROM Tab1;
- value_expression:分区值表达式。
- timeCol:元素排序的时间字段。
- rowCount:定义根据当前行开始向前追溯几行元素。
案例:最新输出的一条数据的 sum 聚合结果是最近 5 行数据的 amount 之和。
CREATE TABLE over_window_row (order_id BIGINT,product BIGINT,amount BIGINT,order_time as cast(CURRENT_TIMESTAMP as TIMESTAMP(3)),WATERMARK FOR order_time AS order_time - INTERVAL '0.001' SECOND
) WITH ('connector' = 'datagen','rows-per-second' = '1','fields.order_id.min' = '1','fields.order_id.max' = '2','fields.amount.min' = '1','fields.amount.max' = '2','fields.product.min' = '1','fields.product.max' = '2'
);SELECT product, order_time, amount,SUM(amount) OVER (PARTITION BY productORDER BY order_time-- 标识统计范围是一个 product 的最近 5 行数据ROWS BETWEEN 5 PRECEDING AND CURRENT ROW) AS five_rows_amount_sum
FROM over_window_row;
结果如下:
- 📢博客主页:https://lansonli.blog.csdn.net
- 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
- 📢本文由 Lansonli 原创,首发于 CSDN博客🙉
- 📢停下休息的时候不要忘了别人还在奔跑,希望大家抓紧时间学习,全力奔赴更美好的生活✨
相关文章:

大数据Flink(一百一十七):Flink SQL的窗口操作
文章目录 Flink SQL的窗口操作 一、窗口的概述 二、Group Windows 1、滚动窗口(TUMBLE) 2、滑动窗口(HOP) 3、Session 窗口(SESSION&am…...

【西电电装实习】6. 手装无人机的蓝牙断连debug
文章目录 前言零、闪灯状态零零、翻滚角,俯仰角,偏航角一、问题描述二、现象解释三、解决方案参考文献 前言 在 西电无人机电装实习 时遇到的问题使用蓝牙芯片 CH582F。沁恒的蓝牙芯片CH582F是一款集成了BLE(Bluetooth Low Energy࿰…...

AIGC实战之如何构建出更好的大模型RAG系统
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。…...

【数据结构-差分】力扣1589. 所有排列中的最大和
有一个整数数组 nums ,和一个查询数组 requests ,其中 requests[i] [starti, endi] 。第 i 个查询求 nums[starti] nums[starti 1] … nums[endi - 1] nums[endi] 的结果 ,starti 和 endi 数组索引都是 从 0 开始 的。 你可以任意排列…...

Spark部署文档
Spark Local环境部署 下载地址 https://dlcdn.apache.org/spark/spark-3.2.0/spark-3.2.0-bin-hadoop3.2.tgz 条件 PYTHON 推荐3.8JDK 1.8 Anaconda On Linux 安装 本次课程的Python环境需要安装到Linux(虚拟机)和Windows(本机)上 参见最下方, 附: Anaconda On Linux 安…...

Broadcast:Android中实现组件及进程间通信
目录 一,Broadcast和BroadcastReceiver 1,简介 2,广播使用 二,静态注册和动态注册 三,无序广播和有序广播 1,有序广播的使用 2,有序广播的截断 3,有序广播的信息传递 四&am…...
5分钟熟练上手ES的具体使用
5分钟上手ES的具体使用 相信有很多同学想要去学习elk时会使用docker等一些方式去下载相关程序,但提到真正去使用es的一系列操作时又会知之甚少。于是这一篇博客应运而生。 本文就以下载好elk/efk系统后应该如何去使用为例,介绍es的具体操作。 es关键字…...

lambda 自调用递归
从前序与中序遍历序列构造二叉树 官方解析实在是记不住,翻别人的题解发现了一个有意思的写法 class Solution { public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {auto dfs [](auto&& dfs, auto&&…...

mac中git操作账号的删除
命令行玩的很溜的可以跳过 找到钥匙串访问 搜github、gitee就行了...

AI Agent的20个趋势洞察
结论整理自【QuestMobile2024 AI智能体应用洞察半年报】: AI原生应用(APP)一路高歌;豆包用户突破3000万;TOP10 APP以综合类应用为主。无论何种类型的AIGC APP都以智能体为“抓手”,专注于解决各种细分场景中的问题&am…...
Spring Boot-定时任务问题
Spring Boot 定时任务问题及其解决方案 1. 引言 在企业级应用中,定时任务是一项常见需求,通常用于自动化执行某些操作,如数据备份、日志清理、系统监控等。Spring Boot 提供了简洁易用的定时任务机制,允许开发者通过简单的配置来…...

从混乱到清晰!借助Kimi掌握螺旋型论文结构的秘诀!
AIPaperGPT,论文写作神器~ https://www.aipapergpt.com/ 写学术论文有时会让人感到头疼,特别是在组织结构和理清思路时,往往觉得无从下手。 其实,找到合适的结构不仅能帮你清晰地表达研究成果,还能让你的论文更有说…...
中国电子学会202306青少年软件编程(Python)等级考试试卷(二级)真题
一、单选题(共25题,每题2分,共50分) 1、运行以下程序,如果通过键盘先后输入的数是1和3,输出的结果是?( ) a = int(input()) b = int(input()) if a < b:a = b print(a)A. 3 1 B. 1 3 C. 1 D. 3 2、运行以下程序,输出的结果是?( ) n = 10 s = 0 m = 1 while…...

样本册3D翻页电子版和印刷版同时拥有是一种什么体验
在数字化时代,样本册3D翻页电子版的兴起,让传统印刷版样本册面临着前所未有的挑战。与此同时,许多企业也开始尝试将两者相结合,以满足更多元化的市场需求。那么,拥有一份既具备数字化优势,又保留传统印刷…...

8586 括号匹配检验
### 思路 1. **初始化栈**:创建一个空栈用于存储左括号。 2. **遍历字符串**:逐个字符检查: - 如果是左括号(( 或 [),则入栈。 - 如果是右括号() 或 ]),则检查栈是…...

案例精选 | 聚铭助力河北省某市公安局筑牢网络安全防护屏障
近年来,各级公安机关积极响应信息化发展趋势,致力于提升公安工作的效能与核心战斗力。河北省某市公安局作为主管全市公安工作的市政府部门,承担着打击违法犯罪、维护社会稳定的重任。随着信息化建设的推进,局内系统数量、种类及数…...

VBS学习2:问题解决(文件中含义中文运行报错或者中文乱码)
文件中含义中文运行报错或者中文乱码 问题 msgbox"fdsfdsf大蘇打撒旦dsfsdffsdfsd发斯蒂芬斯蒂芬"解决 文件编码修改成GB2312...

首次揭秘行业内幕!范罗士、希喂、有哈、小米、安德迈宠物空气净化器实测分析
前段时间有个朋友来我家做客,看到我家三只长毛猫,家里还是干干净净的,他家一只短毛猫都猫毛满天飞。也是很细心,留意到我家猫拉完粑粑后,我立刻就去把宠物空气净化器开上了,他一点味都没闻到。 回家后立刻…...
1267:【例9.11】01背包问题(信奥一本通)
题目链接:信息学奥赛一本通(C版)在线评测系统 (ssoier.cn) 今天刚看完卡尔大哥讲解的01背包,今天手敲了一遍,还是很多问题,只能说自己还是刷题太少或者说是没理解到位。 代码如下 # include <iostrea…...

信息化时代下的高标准农田灌区:变革与机遇并存
在信息化时代的浪潮中,高标准农田灌区的建设与管理正经历着前所未有的变革,这既是一个挑战重重的历程,也孕育着无限的发展机遇。随着物联网、大数据、云计算以及人工智能等先进技术的飞速发展与融合应用,传统的农田灌溉模式正在被…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...

倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...

CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space
问题:IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案:将编译的堆内存增加一点 位置:设置setting-》构建菜单build-》编译器Complier...
MySQL基本操作(续)
第3章:MySQL基本操作(续) 3.3 表操作 表是关系型数据库中存储数据的基本结构,由行和列组成。在MySQL中,表操作包括创建表、查看表结构、修改表和删除表等。本节将详细介绍这些操作。 3.3.1 创建表 在MySQL中&#…...