FlinkSql系列8之TopN&去重
前言
本次主要记录FLinkSql中的TopN以及去重。
一、TopN
建立数据源表
CREATE TABLE source_table5(
--姓名
`name` STRING,
--班级
`class_id` BIGINT,
--分数
`score` BIGINT,
--事件时间
`row_time` TIMESTAMP(3),
--watermark设置
WATERMARK for row_time AS row_time
) WITH (
'connector' = 'kafka',
'topic' = 'flinksql002',
'properties.bootstrap.servers' = 'xxxx:9092',
'properties.group.id' = 'testGroup',
'scan.startup.mode' = 'latest-offset',
'format' = 'csv'
)
场景:统计每个班级的前三名
SELECT
name,
class_id,
score,
row_time
FROM (
SELECT
name,
class_id,
score,
row_time,
ROW_NUMBER() OVER(
PARTITION BY class_id
ORDER BY score DESC) as rownum
FROM source_table5
) WHERE rownum<=3;
测试截图展示:
可以看到随着时间的推移,数据到来,已经输出三条了
紧接着这里我们又来一条比之前分数高的,可以看下输出结果,之前的一条被撤回了
注意:
这里为什么数据会有撤回流,是因为在整个流式计算中,数据源源不断的到来,而我们并没有划定窗口的界限,因此相当于flink缓存了中间所有数据的状态,然后每次都要筛选一遍,得出结果,这对于大状态很容易有问题!
二、WindowTopN
源表依然是上面建的表
下面我们的场景是统计每个班级在一分钟内的时间窗口内的前三名的情况。
SELECT
name,
class_id,
score,
window_start,
window_end
FROM (
SELECT
name,
class_id,
score,..
window_start,
window_end,
ROW_NUMBER() OVER(
PARTITION BY window_start,window_end,class_id
ORDER BY score DESC) as rownum
FROM (
SELECT
name,
class_id,
max(score) as score,
window_start,
window_end
FROM
TABLE(
TUMBLE(
TABLE source_table5,
DESCRIPTOR(row_time),
INTERVAL '1' MINUTE))
GROUP BY window_start,window_end,class_id,name)) WHERE rownum<=3
这里当我们最后输入这个数据的时候就会触发整个计算
计算的结果
这里有个注意点就是这里的模式是固定的:直接写子查询那一段是报错的,会报错
因此这里是有模板的:
SELECT [column_list]
FROM (
SELECT [column_list],
ROW_NUMBER() OVER (PARTITION BY window_start, window_end [, col_key1...]
ORDER BY col1 [asc|desc][, col2 [asc|desc]...]) AS rownum
FROM table_name) -- windowing TVF
WHERE rownum <= N [AND conditions]
需要严格遵守整个模板才可以。
三、Deduplication
本次场景来实现对以一个指标下的数据的去重:
创建数据源表:
CREATE TABLE source_table8(
--用户id
`user_id` BIGINT,
--用户等级
`user_level` STRING,
--访问时间
`row_time` TIMESTAMP(3),
--watermark设置
WATERMARK FOR row_time AS row_time
) WITH (
'connector' = 'kafka',
'topic' = 'flinksql002',
'properties.bootstrap.servers' = 'xxxx:9092',
'properties.group.id' = 'testGroup',
'scan.startup.mode' = 'latest-offset',
'format' = 'csv'
)
执行sql:
SELECT
user_level,
count(1) as uv
FROM(
SELECT
user_id,
user_level,
ROW_NUMBER() OVER(
PARTITION BY user_id
ORDER BY row_time) as rownum
FROM
source_table8
)
WHERE rownum = 1
GROUP BY
user_level
总结
本次主要记录TopN以及Winodow的TopN,需要注意的是这还是有模板可参考的,最后还用ROW_NUMBER() 进行去重的操作。