27、Flink 的SQL之SELECT (Top-N、Window Top-N 窗口 Top-N 和 Window Deduplication 窗口去重)介绍及详细示例(6)

Flink 系列文章

一、Flink 专栏

Flink 专栏系统介绍某一知识点,并辅以具体的示例进行说明。

  • 1、Flink 部署系列
    本部分介绍Flink的部署、配置相关基础内容。

  • 2、Flink基础系列
    本部分介绍Flink 的基础部分,比如术语、架构、编程模型、编程指南、基本的datastream api用法、四大基石等内容。

  • 3、Flik Table API和SQL基础系列
    本部分介绍Flink Table Api和SQL的基本用法,比如Table API和SQL创建库、表用法、查询、窗口函数、catalog等等内容。

  • 4、Flik Table API和SQL提高与应用系列
    本部分是table api 和sql的应用部分,和实际的生产应用联系更为密切,以及有一定开发难度的内容。

  • 5、Flink 监控系列
    本部分和实际的运维、监控工作相关。

二、Flink 示例专栏

Flink 示例专栏是 Flink 专栏的辅助说明,一般不会介绍知识点的信息,更多的是提供一个一个可以具体使用的示例。本专栏不再分目录,通过链接即可看出介绍的内容。

两专栏的所有文章入口点击:Flink 系列文章汇总索引



本文介绍了Flink 的Top-N 、window Top-N以及窗口去重 及具体的运行示例。
本文依赖flink和kafka集群能正常使用。
本文分为3个部分,即top-n、window top-n和window去重,并且每个内容均以验证通过示例进行说明。
本文的示例是在Flink 1.17版本上验证通过的。

一、TOP-N

前 N 个查询要求按列排序的 N 个最小值或最大值。最小值和最大值集都被视为前 N 个查询。在需要仅显示条件上批处理/流式处理表中最底部的 N 条记录或 N 条最前的记录的情况下,前 N 个查询非常有用。此结果集可用于进一步分析。

Flink 使用 OVER 窗口子句和过滤条件的组合来表达 Top-N 查询。借助 OVER window PARTITION BY 子句的强大功能,Flink 还支持每组 Top-N。例如,每个类别实时销售额最高的前五种产品。批处理表和流式处理表上的 SQL 支持前 N 个查询。

下面显示了 Top-N 语句的语法:

SELECT [column_list]
FROM (
   SELECT [column_list],
     ROW_NUMBER() OVER ([PARTITION BY col1[, col2...]]
       ORDER BY col1 [asc|desc][, col2 [asc|desc]...]) AS rownum
   FROM table_name)
WHERE rownum <= N [AND conditions]


参数说明:

  • ROW_NUMBER():根据分区中行的顺序,为每一行分配一个唯一的序列号,从 1 开始。目前(截至版本Flink 1.17),我们仅支持ROW_NUMBER作为窗口功能。将来,我们将支持 RANK() 和 DENSE_RANK()。
  • PARTITION BY col1[, col2…]:指定分区列。每个分区都有一个前 N 个结果。
  • ORDER BY col1 [asc|desc][, col2 [asc|desc]…]:指定排序列。不同列的排序方向可能不同。
  • WHERE rownum <= N:Flink 需要 rownum <= N 才能识别此查询是 Top-N 查询。N 表示将保留的 N 条最小或最大记录。
  • [AND 条件]:可以在 where 子句中添加其他条件,但其他条件只能使用 AND 连词与 rownum <= N 组合。

必须严格遵循上述模式,否则优化程序将无法转换查询。

TopN 查询是“结果更新”。Flink SQL 会根据顺序键对输入数据流进行排序,所以如果前 N 条记录被更改,更改后的记录将作为撤回/更新记录发送到下游。建议使用支持更新的存储作为 Top-N 查询的接收器。此外,如果需要将前 N 条记录存储在外部存储中,则结果表应与 Top-N 查询具有相同的唯一键。

Top-N 查询的唯一键是分区列和 rownum 列的组合。Top-N 查询还可以导出上游的唯一键。以下面的作业为例,假设product_id是 ShopSales 的唯一键,那么 Top-N 查询的唯一键是 [category, rownum] 和 [product_id]。

以下示例演示如何在流式处理表上使用 Top-N 指定 SQL 查询。这是一个示例,用于获取我们上面提到的“每个类别实时销售额最高的前五种产品”。

----1、建表
CREATE TABLE shopSales (
  product_id   STRING,
  category     STRING,
  product_name STRING,
  sales        BIGINT
) WITH (
  'connector' = 'kafka',
  'topic' = 'shopSales_topic',
  'properties.bootstrap.servers' = 'server1:9092,server2:9092,server3:9092',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'csv'
);
----2、表数据
Flink SQL> select * from shopSales;
+----+--------------------------------+--------------------------------+--------------------------------+----------------------+
| op |                     product_id |                       category |                   product_name |                sales |
+----+--------------------------------+--------------------------------+--------------------------------+----------------------+
| +I |                              1 |                              1 |                             p1 |                   15 |
| +I |                              2 |                              2 |                             p2 |                   13 |
| +I |                              3 |                              1 |                             p3 |                  345 |
| +I |                              4 |                              4 |                             p4 |                   25 |
| +I |                              5 |                              1 |                             p5 |                  100 |
| +I |                              6 |                              1 |                             p6 |                   35 |
| +I |                              7 |                              2 |                             p7 |                   27 |
| +I |                              8 |                              3 |                             p8 |                   65 |
| +I |                              9 |                              1 |                             p9 |                   98 |
| +I |                             10 |                              1 |                            p10 |                   89 |
| +I |                             12 |                              3 |                            p11 |                   76 |
| +I |                             13 |                              4 |                            p12 |                   67 |
| +I |                             14 |                              5 |                            p22 |                    9 |
| +I |                             15 |                              4 |                            p32 |                  180 |
| +I |                             16 |                              3 |                           p109 |                  984 |
| +I |                             17 |                              5 |                           p123 |                  500 |
| +I |                             18 |                              2 |                           p223 |                 1000 |

----3、查表内前5销售数据,倒序查
Flink SQL> SELECT *
> FROM (
>   SELECT *,
>     ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS row_num
>   FROM shopSales)
> WHERE row_num <= 5;
+----+--------------------------------+--------------------------------+--------------------------------+----------------------+----------------------+
| op |                     product_id |                       category |                   product_name |                sales |              row_num |
+----+--------------------------------+--------------------------------+--------------------------------+----------------------+----------------------+
| +I |                              1 |                              1 |                             p1 |                   15 |                    1 |
| +I |                              2 |                              2 |                             p2 |                   13 |                    1 |
| -U |                              1 |                              1 |                             p1 |                   15 |                    1 |
| +U |                              3 |                              1 |                             p3 |                  345 |                    1 |
| +I |                              1 |                              1 |                             p1 |                   15 |                    2 |
| +I |                              4 |                              4 |                             p4 |                   25 |                    1 |
| -U |                              1 |                              1 |                             p1 |                   15 |                    2 |
| +U |                              5 |                              1 |                             p5 |                  100 |                    2 |
| +I |                              1 |                              1 |                             p1 |                   15 |                    3 |
| -U |                              1 |                              1 |                             p1 |                   15 |                    3 |
| +U |                              6 |                              1 |                             p6 |                   35 |                    3 |
| +I |                              1 |                              1 |                             p1 |                   15 |                    4 |
| -U |                              2 |                              2 |                             p2 |                   13 |                    1 |
| +U |                              7 |                              2 |                             p7 |                   27 |                    1 |
| +I |                              2 |                              2 |                             p2 |                   13 |                    2 |
| +I |                              8 |                              3 |                             p8 |                   65 |                    1 |
| -U |                              6 |                              1 |                             p6 |                   35 |                    3 |
| +U |                              9 |                              1 |                             p9 |                   98 |                    3 |
| -U |                              1 |                              1 |                             p1 |                   15 |                    4 |
| +U |                              6 |                              1 |                             p6 |                   35 |                    4 |
| +I |                              1 |                              1 |                             p1 |                   15 |                    5 |
| -U |                              6 |                              1 |                             p6 |                   35 |                    4 |
| +U |                             10 |                              1 |                            p10 |                   89 |                    4 |
| -U |                              1 |                              1 |                             p1 |                   15 |                    5 |
| +U |                              6 |                              1 |                             p6 |                   35 |                    5 |
| -U |                              8 |                              3 |                             p8 |                   65 |                    1 |
| +U |                             12 |                              3 |                            p11 |                   76 |                    1 |
| +I |                              8 |                              3 |                             p8 |                   65 |                    2 |
| -U |                              4 |                              4 |                             p4 |                   25 |                    1 |
| +U |                             13 |                              4 |                            p12 |                   67 |                    1 |
| +I |                              4 |                              4 |                             p4 |                   25 |                    2 |
| +I |                             14 |                              5 |                            p22 |                    9 |                    1 |
| -U |                             13 |                              4 |                            p12 |                   67 |                    1 |
| +U |                             15 |                              4 |                            p32 |                  180 |                    1 |
| -U |                              4 |                              4 |                             p4 |                   25 |                    2 |
| +U |                             13 |                              4 |                            p12 |                   67 |                    2 |
| +I |                              4 |                              4 |                             p4 |                   25 |                    3 |
| -U |                             12 |                              3 |                            p11 |                   76 |                    1 |
| +U |                             16 |                              3 |                           p109 |                  984 |                    1 |
| -U |                              8 |                              3 |                             p8 |                   65 |                    2 |
| +U |                             12 |                              3 |                            p11 |                   76 |                    2 |
| +I |                              8 |                              3 |                             p8 |                   65 |                    3 |
| -U |                             14 |                              5 |                            p22 |                    9 |                    1 |
| +U |                             17 |                              5 |                           p123 |                  500 |                    1 |
| +I |                             14 |                              5 |                            p22 |                    9 |                    2 |
| -U |                              7 |                              2 |                             p7 |                   27 |                    1 |
| +U |                             18 |                              2 |                           p223 |                 1000 |                    1 |
| -U |                              2 |                              2 |                             p2 |                   13 |                    2 |
| +U |                              7 |                              2 |                             p7 |                   27 |                    2 |
| +I |                              2 |                              2 |                             p2 |                   13 |                    3 |

1、No Ranking Output Optimization(无排名输出优化)

如上所述,rownum 字段将作为唯一键的一个字段写入结果表中,这可能会导致大量记录被写入结果表。例如,当排名 9 的记录(例如 product-1001)更新且其排名升级到 1 时,排名 1 ~ 9 的所有记录将作为更新消息输出到结果表中。如果结果表接收的数据过多,就会成为SQL作业的瓶颈。

优化方法是省略 Top-N 查询的外部 SELECT 子句中的 rownum 字段。这是合理的,因为前 N 条记录的数量通常不大,因此消费者可以快速对记录进行排序。如果没有 rownum 字段,在上面的例子中,只需要将更改的记录 (product-1001) 发送到下游,这可以减少结果表的大量 IO。

以下示例演示如何以这种方式优化上述 Top-N 示例:
本示例是基于上述示例中的表结构、数据,比较二者的查询结果。

SELECT product_id, category, product_name, sales
FROM (
  SELECT *,
    ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS row_num
  FROM shopSales)
WHERE row_num <= 5;

Flink SQL> SELECT product_id, category, product_name, sales
> FROM (
>   SELECT *,
>     ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS row_num
>   FROM shopSales)
> WHERE row_num <= 5;
+----+--------------------------------+--------------------------------+--------------------------------+----------------------+
| op |                     product_id |                       category |                   product_name |                sales |
+----+--------------------------------+--------------------------------+--------------------------------+----------------------+
| +I |                              1 |                              1 |                             p1 |                   15 |
| +I |                              2 |                              2 |                             p2 |                   13 |
| +I |                              3 |                              1 |                             p3 |                  345 |
| +I |                              4 |                              4 |                             p4 |                   25 |
| +I |                              5 |                              1 |                             p5 |                  100 |
| +I |                              6 |                              1 |                             p6 |                   35 |
| +I |                              7 |                              2 |                             p7 |                   27 |
| +I |                              8 |                              3 |                             p8 |                   65 |
| +I |                              9 |                              1 |                             p9 |                   98 |
| -D |                              1 |                              1 |                             p1 |                   15 |
| +I |                             10 |                              1 |                            p10 |                   89 |
| +I |                             12 |                              3 |                            p11 |                   76 |
| +I |                             13 |                              4 |                            p12 |                   67 |
| +I |                             14 |                              5 |                            p22 |                    9 |
| +I |                             15 |                              4 |                            p32 |                  180 |
| +I |                             16 |                              3 |                           p109 |                  984 |
| +I |                             17 |                              5 |                           p123 |                  500 |
| +I |                             18 |                              2 |                           p223 |                 1000 |

为了将上述查询输出到外部存储并获得正确的结果,外部存储必须与 Top-N 查询具有相同的唯一键。在上面的示例查询中,如果product_id是查询的唯一键,则外部表也应具有product_id作为唯一键。

二、Window Top-N

Window Top-N 是一个特殊的 Top-N,它返回每个窗口和其他分区键的 N 个最小值或最大值。

对于流式处理查询,与连续表上的常规 Top-N 不同,窗口 Top-N 不会发出中间结果,而只会发出最终结果,即窗口末尾的前 N 条记录总数。此外,窗口 Top-N 在不再需要时会清除所有中间状态。因此,如果用户不需要按记录更新结果,则窗口 Top-N 查询具有更好的性能。通常,Window Top-N直接与Windowing TVF一起使用。此外,Window Top-N可以与基于窗口TVF的其他操作一起使用,例如窗口聚合,窗口TopN和窗口联接。

Window Top-N can be defined in the same syntax as regular Top-N, see Top-N documentation for more information. Besides that, Window Top-N requires the PARTITION BY clause contains window_start and window_end columns of the relation applied Windowing TVF or Window Aggregation. Otherwise, the optimizer won’t be able to translate the query.
可以使用与常规 Top-N 相同的语法定义窗口 Top-N。除此之外,Window Top-N 要求 PARTITION BY 子句包含应用窗口 TVF 或窗口聚合的关系的window_start和window_end列。否则,优化程序将无法转换查询。

The following shows the syntax of the Window Top-N statement:

1、Window Top-N 语法

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) -- relation applied windowing TVF
WHERE rownum <= N [AND conditions]

2、Window Top-N follows after Window Aggregation

以下示例演示如何计算每个滚动 5 分钟窗口内销售额最高的前 3 个订单。

----1、建表,表必须有时间属性的列,加水印
# 不加水印 ,报异常:The window function requires the timecol is a time attribute type, but is TIMESTAMP(3).
#  proctime as PROCTIME() 报异常: Processing time Window TopN is not supported yet.
CREATE TABLE orders (
    order_id    STRING,
    price       DECIMAL(32,2),
    order_time  TIMESTAMP(3),
    WATERMARK FOR order_time AS order_time - INTERVAL '1' SECOND
) WITH (
    'connector' = 'kafka',
    'topic' = 'orders_topic',
    'scan.startup.mode' = 'earliest-offset',
    'properties.bootstrap.servers' = 'server1:9092,server2:9092,server3:9092',
    'format' = 'csv'
);

Flink SQL> desc orders;
+------------+------------------------+------+-----+--------+------------------------------------+
|       name |                   type | null | key | extras |                          watermark |
+------------+------------------------+------+-----+--------+------------------------------------+
|   order_id |                 STRING | TRUE |     |        |                                    |
|      price |         DECIMAL(32, 2) | TRUE |     |        |                                    |
| order_time | TIMESTAMP(3) *ROWTIME* | TRUE |     |        | `order_time` - INTERVAL '1' SECOND |
+------------+------------------------+------+-----+--------+------------------------------------+

----2、查询数据

Flink SQL>  select * from orders;
+----+--------------------------------+------------------------------------+-------------------------+
| op |                       order_id |                              price |              order_time |
+----+--------------------------------+------------------------------------+-------------------------+
| +I |                              1 |                              10.00 | 2023-09-25 10:23:18.000 |
| +I |                              2 |                              20.00 | 2023-09-25 10:24:18.000 |
| +I |                              3 |                              30.00 | 2023-09-25 10:25:28.000 |
| +I |                              4 |                              40.00 | 2023-09-25 10:26:38.000 |
| +I |                              5 |                              10.00 | 2023-09-25 10:27:48.000 |
| +I |                              6 |                              20.00 | 2023-09-25 10:23:18.000 |
| +I |                             11 |                              10.00 | 2023-09-25 10:28:18.000 |
| +I |                             12 |                              20.00 | 2023-09-25 10:29:18.000 |
| +I |                             13 |                              30.00 | 2023-09-25 10:30:28.000 |
| +I |                             14 |                              40.00 | 2023-09-25 10:29:38.000 |
| +I |                             15 |                              10.00 | 2023-09-25 10:27:48.000 |
| +I |                             16 |                              20.00 | 2023-09-25 10:28:18.000 |

----3、验证window top-n

Flink SQL> SELECT *
>   FROM (
>     SELECT *, ROW_NUMBER() OVER (PARTITION BY window_start, window_end ORDER BY s_price DESC) as rownum
>     FROM (
>       SELECT window_start, window_end, order_id, SUM(price) as s_price, COUNT(*) as cnt
>       FROM TABLE(
>         TUMBLE(TABLE orders, DESCRIPTOR(order_time), INTERVAL '5' MINUTES))
>       GROUP BY window_start, window_end, order_id
>     )
>   ) WHERE rownum <= 3;
+----+-------------------------+-------------------------+--------------------------------+------------------------------------------+----------------------+----------------------+
| op |            window_start |              window_end |                       order_id |                                  s_price |                  cnt |               rownum |
+----+-------------------------+-------------------------+--------------------------------+------------------------------------------+----------------------+----------------------+
| +I | 2023-09-25 10:20:00.000 | 2023-09-25 10:25:00.000 |                              2 |                                    20.00 |                    1 |                    1 |
| +I | 2023-09-25 10:20:00.000 | 2023-09-25 10:25:00.000 |                              6 |                                    20.00 |                    1 |                    2 |
| +I | 2023-09-25 10:20:00.000 | 2023-09-25 10:25:00.000 |                              1 |                                    10.00 |                    1 |                    3 |

3、Window Top-N follows after Windowing TVF

以下示例显示如何计算每个滚动 10 分钟窗口价格最高的前 3 个订单。

# 表结构与数据参考上文示例
Flink SQL> SELECT *
>   FROM (
>     SELECT *, ROW_NUMBER() OVER (PARTITION BY window_start, window_end ORDER BY price DESC) as rownum
>     FROM TABLE(
>                TUMBLE(TABLE orders, DESCRIPTOR(order_time), INTERVAL '10' MINUTES))
>   ) WHERE rownum <= 3;
+----+--------------------------------+------------------------------------+-------------------------+-------------------------+-------------------------+-------------------------+----------------------+
| op |                       order_id |                              price |              order_time |            window_start |              window_end |             window_time |               rownum |
+----+--------------------------------+------------------------------------+-------------------------+-------------------------+-------------------------+-------------------------+----------------------+
| +I |                              4 |                              40.00 | 2023-09-25 10:26:38.000 | 2023-09-25 10:20:00.000 | 2023-09-25 10:30:00.000 | 2023-09-25 10:29:59.999 |                    1 |
| +I |                             14 |                              40.00 | 2023-09-25 10:29:38.000 | 2023-09-25 10:20:00.000 | 2023-09-25 10:30:00.000 | 2023-09-25 10:29:59.999 |                    2 |
| +I |                              3 |                              30.00 | 2023-09-25 10:25:28.000 | 2023-09-25 10:20:00.000 | 2023-09-25 10:30:00.000 | 2023-09-25 10:29:59.999 |                    3 |

3、Limitation

截至版本Flink 1.17,Flink 仅支持具有 Tumble Windows、Hop Windows 和 Cumulate Windows 的 Windowing TVF 的 Window Top-N 。Window Top-N 的 Windowing TVF 与会话窗口将在不久的将来得到支持。

三、Window Deduplication

窗口重复数据删除是一种特殊的重复数据删除,可删除在一组列上重复的行,为每个窗口和分区键保留第一个或最后一个行。

对于流式处理查询,与连续表上的常规重复数据删除不同,窗口重复数据删除不会发出中间结果,而只会在窗口结束时发出最终结果。此外,窗口重复数据删除会在不再需要时清除所有中间状态。因此,如果用户不需要更新每条记录的结果,则窗口重复数据删除查询具有更好的性能。通常,窗口重复数据删除直接与窗口化 TVF 一起使用。此外,窗口重复数据删除还可以与基于窗口化TVF的其他操作一起使用,例如窗口聚合,窗口TopN和窗口联接。

窗口重复数据删除可以使用与常规重复数据删除相同的语法进行定义。除此之外,窗口重复数据删除要求 PARTITION BY 子句包含关系的window_start和window_end列。否则,优化程序将无法转换查询。

Flink 使用 ROW_NUMBER() 来删除重复项,就像 Window Top-N 查询的方式一样。理论上,窗口重复数据删除是窗口顶部 N 的一个特例,其中 N 是 1,并按处理时间或事件时间排序。

1、语法

下面显示了窗口重复数据删除语句的语法:

SELECT [column_list]
FROM (
   SELECT [column_list],
     ROW_NUMBER() OVER (PARTITION BY window_start, window_end [, col_key1...]
       ORDER BY time_attr [asc|desc]) AS rownum
   FROM table_name) -- relation applied windowing TVF
WHERE (rownum = 1 | rownum <=1 | rownum < 2) [AND conditions]

# ROW_NUMBER():为每一行分配一个唯一的序列号,从 1 开始。
# 按 window_start、window_end [、col_key1...] 分区:指定包含window_start、window_end和其他分区键的分区列。
# 按time_attr排序 [asc|desc]:指定排序列,它必须具有时间属性。截至 Flink 1.17版本 支持处理时间属性和事件时间属性。按ASC排序意味着保留第一行,按DESC排序意味着保留最后一行。
# 其中(rownum  = 1 | rownum  <=1 | rownum  < 2):rownum  = 1 | rownum  <=1 |优化程序需要 rownum < 2 才能识别查询可以转换为窗口重复数据删除。

必须完全遵循上述模式,否则优化程序不会将查询转换为窗口重复数据删除。

2、示例

下面的示例演示如何保留每 10 分钟滚动窗口的最后一条记录。

----1、建表,表必须有时间属性的列,加水印
# 不加水印 ,报异常:The window function requires the timecol is a time attribute type, but is TIMESTAMP(3).
#  proctime as PROCTIME() 报异常: Processing time Window TopN is not supported yet.
CREATE TABLE orders (
    order_id    STRING,
    price       DECIMAL(32,2),
    order_time  TIMESTAMP(3),
    WATERMARK FOR order_time AS order_time - INTERVAL '1' SECOND
) WITH (
    'connector' = 'kafka',
    'topic' = 'orders_topic',
    'scan.startup.mode' = 'earliest-offset',
    'properties.bootstrap.servers' = 'server1:9092,server2:9092,server3:9092',
    'format' = 'csv'
);

Flink SQL> desc orders;
+------------+------------------------+------+-----+--------+------------------------------------+
|       name |                   type | null | key | extras |                          watermark |
+------------+------------------------+------+-----+--------+------------------------------------+
|   order_id |                 STRING | TRUE |     |        |                                    |
|      price |         DECIMAL(32, 2) | TRUE |     |        |                                    |
| order_time | TIMESTAMP(3) *ROWTIME* | TRUE |     |        | `order_time` - INTERVAL '1' SECOND |
+------------+------------------------+------+-----+--------+------------------------------------+

----2、查询数据

Flink SQL> select * from orders;
+----+--------------------------------+------------------------------------+-------------------------+
| op |                       order_id |                              price |              order_time |
+----+--------------------------------+------------------------------------+-------------------------+
| +I |                              1 |                              10.00 | 2023-09-25 10:23:18.000 |
| +I |                              2 |                              20.00 | 2023-09-25 10:24:18.000 |
| +I |                              3 |                              30.00 | 2023-09-25 10:25:28.000 |
| +I |                              4 |                              40.00 | 2023-09-25 10:26:38.000 |
| +I |                              5 |                              10.00 | 2023-09-25 10:27:48.000 |
| +I |                              6 |                              20.00 | 2023-09-25 10:23:18.000 |
| +I |                             11 |                              10.00 | 2023-09-25 10:28:18.000 |
| +I |                             12 |                              20.00 | 2023-09-25 10:29:18.000 |
| +I |                             13 |                              30.00 | 2023-09-25 10:30:28.000 |
| +I |                             14 |                              40.00 | 2023-09-25 10:29:38.000 |
| +I |                             15 |                              10.00 | 2023-09-25 10:27:48.000 |
| +I |                             15 |                              10.00 | 2023-09-25 10:27:48.000 |
| +I |                             16 |                              20.00 | 2023-09-25 10:28:18.000 |
| +I |                             17 |                              50.00 | 2023-09-25 10:37:22.000 |

----3、验证窗口重复数据删除
Flink SQL> 
> SELECT *
>   FROM (
>     SELECT order_time, price, order_id, window_start, window_end, 
>       ROW_NUMBER() OVER (PARTITION BY window_start, window_end ORDER BY order_time DESC) AS rownum
>     FROM TABLE(
>                TUMBLE(TABLE orders, DESCRIPTOR(order_time), INTERVAL '10' MINUTES))
>   ) WHERE rownum <= 1;
+----+-------------------------+------------------------------------+--------------------------------+-------------------------+-------------------------+----------------------+
| op |              order_time |                              price |                       order_id |            window_start |              window_end |               rownum |
+----+-------------------------+------------------------------------+--------------------------------+-------------------------+-------------------------+----------------------+
| +I | 2023-09-25 10:29:38.000 |                              40.00 |                             14 | 2023-09-25 10:20:00.000 | 2023-09-25 10:30:00.000 |                    1 |
| +I | 2023-09-25 10:37:22.000 |                              50.00 |                             17 | 2023-09-25 10:30:00.000 | 2023-09-25 10:40:00.000 |                    1 |


3、限制

1)、Limitation on Window Deduplication which follows after Windowing TVFs directly

截至 Flink 1.17版本,如果窗口重复数据删除在窗口化 TVF 之后进行,则窗口化 TVF 必须与 Tumble Windows、Hop Windows 或Cumulate Windows一起使用,而不是会话窗口。在不久的将来将支持会话窗口。

2)、Limitation on time attribute of order key

截至 Flink 1.17版本,窗口重复数据删除要求订单键必须是事件时间属性,而不是处理时间属性。在不久的将来将支持按处理时间排序。

以上,介绍了Flink 的Top-N 、window Top-N以及窗口去重 及具体的运行示例。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
FlinkSQL 中可以使用 TopN 实现对数据流中某个字段的排序并取出前 N 个数据。TopN 算子适用于一些需要对数据进行排序、筛选的场景,比如热门商品排行、用户行为分析等。 普通 TopN 是指对整个数据流进行排序,取出前 N 条数据。在 FlinkSQL 中,可以使用如下语句实现普通 TopN: ``` SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY column DESC) as rownum FROM table ) t WHERE rownum <= N ``` 其中,ROW_NUMBER() OVER (ORDER BY column DESC) as rownum 表示对表中的某个字段进行降序排序,并为每一行分配一个 rownum,表示该行在排序后的位置。然后在外层 SELECT 语句中筛选出 rownum 小于等于 N 的数据即可。 窗口 TopN 是指对某个时间窗口内的数据进行排序,取出前 N 条数据。在 FlinkSQL 中,可以使用如下语句实现窗口 TopN: ``` SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY window ORDER BY column DESC) as rownum FROM table GROUP BY window, other_column ) t WHERE rownum <= N ``` 其中,ROW_NUMBER() OVER (PARTITION BY window ORDER BY column DESC) as rownum 表示对每个时间窗口内的数据进行排序,并为每一行分配一个 rownum,表示该行在排序后的位置。在外层 SELECT 语句中筛选出 rownum 小于等于 N 的数据即可。需要注意的是,在窗口 TopN 中,需要使用 GROUP BY 将数据按照时间窗口和其他字段进行分组,否则会出现重复数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一瓢一瓢的饮 alanchanchn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值