33、Flink 的Table API 和 SQL 中的时区

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 中关于时区的概念,并以具体的示例进行说明。
本文依赖flink、kafka集群能正常使用。
本文分为5个部分,即TIMESTAMP vs TIMESTAMP_LTZ介绍、时区的作用、时区属性与时区、夏令时支持与流批关于时间的处理区别。
本文的示例是在Flink 1.17版本中运行。

一、时区

Flink 为日期和时间提供了丰富的数据类型, 包括 DATE, TIME, TIMESTAMP, TIMESTAMP_LTZ, INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND (更多详情请参考 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 中的 Date and Time)。 Flink 支持在 session (会话)级别设置时区(更多详情请参考 15、Flink 的table api与sql之流式概念-详解的介绍了动态表、时间属性配置(如何处理更新结果)、时态表、流上的join、流上的确定性以及查询配置 中的 Planner 配置 table.local-time-zone 部分)。 Flink 对多种时间类型和时区的支持使得跨时区的数据处理变得非常容易。

1、TIMESTAMP vs TIMESTAMP_LTZ

1)、TIMESTAMP 类型

  • TIMESTAMP§ 是 TIMESTAMP§ WITHOUT TIME ZONE 的简写, 精度 p 支持的范围是0-9, 默认是6。
  • TIMESTAMP 用于描述年, 月, 日, 小时, 分钟, 秒 和 小数秒对应的时间戳。
  • TIMESTAMP 可以通过一个字符串来指定,例如:
Flink SQL> SELECT TIMESTAMP '1970-01-01 00:00:04.001';
+-------------------------+
| 1970-01-01 00:00:04.001 |
+-------------------------+

2)、TIMESTAMP_LTZ 类型

  • TIMESTAMP_LTZ(p) 是 TIMESTAMP(p) WITH LOCAL TIME ZONE 的简写, 精度 p 支持的范围是0-9, 默认是6。
  • TIMESTAMP_LTZ 用于描述时间线上的绝对时间点, 使用 long 保存从 epoch 至今的毫秒数, 使用int保存毫秒中的纳秒数。 epoch 时间是从 java 的标准 epoch 时间 1970-01-01T00:00:00Z 开始计算。 在计算和可视化时, 每个 TIMESTAMP_LTZ 类型的数据都是使用的 session (会话)中配置的时区。
  • TIMESTAMP_LTZ 没有字符串表达形式因此无法通过字符串来指定, 可以通过一个 long 类型的 epoch 时间来转化(例如: 通过 Java 来产生一个 long 类型的 epoch 时间 System.currentTimeMillis())
Flink SQL> CREATE VIEW T1 AS SELECT TO_TIMESTAMP_LTZ(4001, 3);
Flink SQL> SET 'table.local-time-zone' = 'UTC';
Flink SQL> SELECT * FROM T1;
+---------------------------+
| TO_TIMESTAMP_LTZ(4001, 3) |
+---------------------------+
|   1970-01-01 00:00:04.001 |
+---------------------------+

Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai';
Flink SQL> SELECT * FROM T1;
+---------------------------+
| TO_TIMESTAMP_LTZ(4001, 3) |
+---------------------------+
|   1970-01-01 08:00:04.001 |
+---------------------------+
  • TIMESTAMP_LTZ 可以用于跨时区的计算,因为它是一个基于 epoch 的绝对时间点(比如上例中的 4001 毫秒)代表的就是不同时区的同一个绝对时间点。 补充一个背景知识:在同一个时间点, 全世界所有的机器上执行 System.currentTimeMillis() 都会返回同样的值。 (比如上例中的 4001 milliseconds), 这就是绝对时间的定义。

2、时区的作用

本地时区定义了当前 session(会话)所在的时区, 你可以在 Sql client 或者应用程序中配置。

  • java
    代码片段示例
EnvironmentSettings envSetting = EnvironmentSettings.inStreamingMode();
 TableEnvironment tEnv = TableEnvironment.create(envSetting);

 // 设置为 UTC 时区
 tEnv.getConfig().setLocalTimeZone(ZoneId.of("UTC"));

// 设置为上海时区
 tEnv.getConfig().setLocalTimeZone(ZoneId.of("Asia/Shanghai"));

// 设置为 Los_Angeles 时区
 tEnv.getConfig().setLocalTimeZone(ZoneId.of("America/Los_Angeles"));
  • sql client
-- 设置为 UTC 时区
Flink SQL> SET 'table.local-time-zone' = 'UTC';
[INFO] Execute statement succeed.

-- 设置为上海时区
Flink SQL> SET 'table.local-time-zone' = 'America/Los_Angeles';
[INFO] Execute statement succeed.

-- 设置为Los_Angeles时区
Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai';
[INFO] Execute statement succeed.

session(会话)的时区设置在 Flink SQL 中非常有用, 它的主要用法如下:

1)、确定时间函数的返回值

session (会话)中配置的时区会对以下函数生效。

  • LOCALTIME
  • LOCALTIMESTAMP
  • CURRENT_DATE
  • CURRENT_TIME
  • CURRENT_TIMESTAMP
  • CURRENT_ROW_TIMESTAMP()
  • NOW()
  • PROCTIME()
Flink SQL> SET 'sql-client.execution.result-mode' = 'tableau';
[INFO] Execute statement succeed.

Flink SQL> CREATE VIEW MyView1 AS 
> SELECT LOCALTIME, LOCALTIMESTAMP, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_ROW_TIMESTAMP(), NOW(), PROCTIME();
[INFO] Execute statement succeed.

Flink SQL> DESC MyView1;
+-------------------+-----------------------------+-------+-----+--------+-----------+
|              name |                        type |  null | key | extras | watermark |
+-------------------+-----------------------------+-------+-----+--------+-----------+
|         LOCALTIME |                     TIME(0) | FALSE |     |        |           |
|    LOCALTIMESTAMP |                TIMESTAMP(3) | FALSE |     |        |           |
|      CURRENT_DATE |                        DATE | FALSE |     |        |           |
|      CURRENT_TIME |                     TIME(0) | FALSE |     |        |           |
| CURRENT_TIMESTAMP |            TIMESTAMP_LTZ(3) | FALSE |     |        |           |
|            EXPR$5 |            TIMESTAMP_LTZ(3) | FALSE |     |        |           |
|            EXPR$6 |            TIMESTAMP_LTZ(3) | FALSE |     |        |           |
|            EXPR$7 | TIMESTAMP_LTZ(3) *PROCTIME* | FALSE |     |        |           |
+-------------------+-----------------------------+-------+-----+--------+-----------+
8 rows in set

Flink SQL> SET 'table.local-time-zone' = 'UTC';
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView1;
+----+-----------+-------------------------+--------------+--------------+-------------------------+-------------------------+-------------------------+-------------------------+
| op | LOCALTIME |          LOCALTIMESTAMP | CURRENT_DATE | CURRENT_TIME |       CURRENT_TIMESTAMP |                  EXPR$5 |                  EXPR$6 |                  EXPR$7 |
+----+-----------+-------------------------+--------------+--------------+-------------------------+-------------------------+-------------------------+-------------------------+
| +I |  06:52:14 | 2023-11-10 06:52:14.144 |   2023-11-10 |     06:52:14 | 2023-11-10 06:52:14.144 | 2023-11-10 06:52:14.144 | 2023-11-10 06:52:14.144 | 2023-11-10 06:52:14.145 |
+----+-----------+-------------------------+--------------+--------------+-------------------------+-------------------------+-------------------------+-------------------------+
Received a total of 1 row

Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai';
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView1;
+----+-----------+-------------------------+--------------+--------------+-------------------------+-------------------------+-------------------------+-------------------------+
| op | LOCALTIME |          LOCALTIMESTAMP | CURRENT_DATE | CURRENT_TIME |       CURRENT_TIMESTAMP |                  EXPR$5 |                  EXPR$6 |                  EXPR$7 |
+----+-----------+-------------------------+--------------+--------------+-------------------------+-------------------------+-------------------------+-------------------------+
| +I |  14:52:52 | 2023-11-10 14:52:52.305 |   2023-11-10 |     14:52:52 | 2023-11-10 14:52:52.305 | 2023-11-10 14:52:52.305 | 2023-11-10 14:52:52.305 | 2023-11-10 14:52:52.305 |
+----+-----------+-------------------------+--------------+--------------+-------------------------+-------------------------+-------------------------+-------------------------+
Received a total of 1 row

2)、TIMESTAMP_LTZ 字符串表示

当一个 TIMESTAMP_LTZ 值转为 string 格式时, session 中配置的时区会生效。 例如打印这个值,将类型强制转化为 STRING 类型, 将类型强制转换为 TIMESTAMP ,将 TIMESTAMP 的值转化为 TIMESTAMP_LTZ 类型:

Flink SQL> CREATE VIEW MyView2 AS 
> SELECT TO_TIMESTAMP_LTZ(4001, 3) AS ltz, TIMESTAMP '1970-01-01 00:00:01.001'  AS ntz;
[INFO] Execute statement succeed.

Flink SQL> DESC MyView2;
+------+------------------+-------+-----+--------+-----------+
| name |             type |  null | key | extras | watermark |
+------+------------------+-------+-----+--------+-----------+
|  ltz | TIMESTAMP_LTZ(3) |  TRUE |     |        |           |
|  ntz |     TIMESTAMP(3) | FALSE |     |        |           |
+------+------------------+-------+-----+--------+-----------+
2 rows in set

Flink SQL> SET 'table.local-time-zone' = 'UTC';
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView2;
+----+-------------------------+-------------------------+
| op |                     ltz |                     ntz |
+----+-------------------------+-------------------------+
| +I | 1970-01-01 00:00:04.001 | 1970-01-01 00:00:01.001 |
+----+-------------------------+-------------------------+
Received a total of 1 row

Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai';
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView2;
+----+-------------------------+-------------------------+
| op |                     ltz |                     ntz |
+----+-------------------------+-------------------------+
| +I | 1970-01-01 08:00:04.001 | 1970-01-01 00:00:01.001 |
+----+-------------------------+-------------------------+
Received a total of 1 row

Flink SQL> CREATE VIEW MyView3 AS 
> SELECT ltz, CAST(ltz AS TIMESTAMP(3)), CAST(ltz AS STRING), ntz, CAST(ntz AS TIMESTAMP_LTZ(3)) FROM MyView2;
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView3;
+----+-------------------------+-------------------------+--------------------------------+-------------------------+-------------------------+
| op |                     ltz |                  EXPR$1 |                         EXPR$2 |                     ntz |                  EXPR$4 |
+----+-------------------------+-------------------------+--------------------------------+-------------------------+-------------------------+
| +I | 1970-01-01 08:00:04.001 | 1970-01-01 08:00:04.001 |        1970-01-01 08:00:04.001 | 1970-01-01 00:00:01.001 | 1970-01-01 00:00:01.001 |
+----+-------------------------+-------------------------+--------------------------------+-------------------------+-------------------------+
Received a total of 1 row

3、时间属性和时区

更多时间属性相关的详细介绍, 请参考:15、Flink 的table api与sql之流式概念-详解的介绍了动态表、时间属性配置(如何处理更新结果)、时态表、流上的join、流上的确定性以及查询配置 中的时间属性配置部分。

1)、处理时间和时区

Flink SQL 使用函数 PROCTIME() 来定义处理时间属性, 该函数返回的类型是 TIMESTAMP_LTZ 。

在 Flink1.13 之前, PROCTIME() 函数返回的类型是 TIMESTAMP , 返回值是UTC时区下的 TIMESTAMP 。
例如: 当上海的时间为 2021-11-11 12:00:00 时, PROCTIME() 显示的时间却是错误的 2021-11-11 04:00:00 。 这个问题在 Flink 1.13 中修复了, 因此用户不用再去处理时区的问题了。

PROCTIME() 返回的是本地时区的时间, 使用 TIMESTAMP_LTZ 类型也可以支持夏令时时间。

Flink SQL> SET 'table.local-time-zone' = 'UTC';
[INFO] Execute statement succeed.

Flink SQL> SELECT PROCTIME();
+----+-------------------------+
| op |                  EXPR$0 |
+----+-------------------------+
| +I | 2023-11-10 06:59:30.998 |
+----+-------------------------+
Received a total of 1 row

Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai';
[INFO] Execute statement succeed.

Flink SQL> SELECT PROCTIME();
+----+-------------------------+
| op |                  EXPR$0 |
+----+-------------------------+
| +I | 2023-11-10 14:59:54.031 |
+----+-------------------------+
Received a total of 1 row


Flink SQL> CREATE TABLE MyTable1 (
>                   item STRING,
>                   price DOUBLE,
>                   proctime as PROCTIME()
> ) WITH (
>   'connector' = 'kafka',
>   'topic' = 'MyTable1',
>   'properties.bootstrap.servers' = '192.168.10.41:9092,192.168.10.42:9092,192.168.10.43:9092',
>   'properties.group.id' = 'testGroup',
>   'scan.startup.mode' = 'earliest-offset',
>   'format' = 'csv'
> );
[INFO] Execute statement succeed.

Flink SQL> CREATE VIEW MyView3 AS
>             SELECT
>                 TUMBLE_START(proctime, INTERVAL '10' MINUTES) AS window_start,
>                 TUMBLE_END(proctime, INTERVAL '10' MINUTES) AS window_end,
>                 TUMBLE_PROCTIME(proctime, INTERVAL '10' MINUTES) as window_proctime,
>                 item,
>                 MAX(price) as max_price
>             FROM MyTable1
>                 GROUP BY TUMBLE(proctime, INTERVAL '10' MINUTES), item;
[INFO] Execute statement succeed.

Flink SQL> DESC MyView3;
+-----------------+-----------------------------+-------+-----+--------+-----------+
|            name |                        type |  null | key | extras | watermark |
+-----------------+-----------------------------+-------+-----+--------+-----------+
|    window_start |                TIMESTAMP(3) | FALSE |     |        |           |
|      window_end |                TIMESTAMP(3) | FALSE |     |        |           |
| window_proctime | TIMESTAMP_LTZ(3) *PROCTIME* | FALSE |     |        |           |
|            item |                      STRING |  TRUE |     |        |           |
|       max_price |                      DOUBLE |  TRUE |     |        |           |
+-----------------+-----------------------------+-------+-----+--------+-----------+
5 rows in set

在终端执行以下命令写入数据到 MyTable1 :

[alanchan@server1 bin]$ kafka-console-producer.sh --broker-list server1:9092 --topic MyTable1
>A,1.1
>B,1.2
>A,1.8
>B,2.5
>C,3.8
>

Flink SQL> SET 'table.local-time-zone' = 'UTC';
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView3;
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| op |            window_start |              window_end |         window_proctime |                           item |                      max_price |
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| +I | 2023-11-10 07:10:00.000 | 2023-11-10 07:20:00.000 | 2023-11-10 07:20:00.000 |                              A |                            1.8 |
| +I | 2023-11-10 07:10:00.000 | 2023-11-10 07:20:00.000 | 2023-11-10 07:20:00.000 |                              C |                            3.8 |
| +I | 2023-11-10 07:10:00.000 | 2023-11-10 07:20:00.000 | 2023-11-10 07:20:00.001 |                              B |                            2.5 |
received a total of 3 rows
Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai';
[INFO] Execute statement succeed.

相比在 UTC 时区下的计算结果, 在 Asia/Shanghai 时区下计算的窗口开始时间, 窗口结束时间和窗口处理时间是不同的。

Flink SQL> SELECT * FROM MyView3;
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| op |            window_start |              window_end |         window_proctime |                           item |                      max_price |
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| +I | 2023-11-10 15:10:00.000 | 2023-11-10 15:20:00.000 | 2023-11-10 15:20:00.000 |                              A |                            1.8 |
| +I | 2023-11-10 15:10:00.000 | 2023-11-10 15:20:00.000 | 2023-11-10 15:20:00.000 |                              C |                            3.8 |
| +I | 2023-11-10 15:10:00.000 | 2023-11-10 15:20:00.000 | 2023-11-10 15:20:00.001 |                              B |                            2.5 |
received a total of 3 rows

处理时间窗口是不确定的, 每次运行都会返回不同的窗口和聚合结果。 以上的示例只用于说明时区如何影响处理时间窗口。

2)、事件时间和时区

Flink 支持在 TIMESTAMP 列和 TIMESTAMP_LTZ 列上定义时间属性。

1、TIMESTAMP 上的事件时间属性

如果 source 中的时间用于表示年-月-日-小时-分钟-秒, 通常是一个不带时区的字符串,
例如: 2023-11-13 08:13:40.564。 推荐在 TIMESTAMP 列上定义事件时间属性。

  • 准备测试环境,即表、视图和数据
Flink SQL> CREATE TABLE MyTable2 (
>   item STRING,
>   price DOUBLE,
>   ts TIMESTAMP(3), -- TIMESTAMP data type
>   WATERMARK FOR ts AS ts - INTERVAL '10' SECOND
>    ) WITH (
>   'connector' = 'kafka',
>   'topic' = 'MyTable2',
>   'properties.bootstrap.servers' = '192.168.10.41:9092,192.168.10.42:9092,192.168.10.43:9092',
>   'properties.group.id' = 'testGroup',
>   'scan.startup.mode' = 'earliest-offset',
>   'format' = 'csv'
> );
[INFO] Execute statement succeed.

Flink SQL> CREATE VIEW MyView4 AS
> SELECT
> TUMBLE_START(ts, INTERVAL '10' MINUTES) AS window_start,
> TUMBLE_END(ts, INTERVAL '10' MINUTES) AS window_end,
> TUMBLE_ROWTIME(ts, INTERVAL '10' MINUTES) as window_rowtime,
> item,
> MAX(price) as max_price
> FROM MyTable2
> GROUP BY TUMBLE(ts, INTERVAL '10' MINUTES), item;
[INFO] Execute statement succeed.

Flink SQL> DESC MyView4;
+----------------+------------------------+-------+-----+--------+-----------+
|           name |                   type |  null | key | extras | watermark |
+----------------+------------------------+-------+-----+--------+-----------+
|   window_start |           TIMESTAMP(3) | FALSE |     |        |           |
|     window_end |           TIMESTAMP(3) | FALSE |     |        |           |
| window_rowtime | TIMESTAMP(3) *ROWTIME* |  TRUE |     |        |           |
|           item |                 STRING |  TRUE |     |        |           |
|      max_price |                 DOUBLE |  TRUE |     |        |           |
+----------------+------------------------+-------+-----+--------+-----------+
5 rows in set

在终端执行以下命令用于写入数据到 MyTable2 :

[alanchan@server1 bin]$ kafka-console-producer.sh --broker-list server1:9092 --topic alan_MyTable2
>A,1.1,2023-11-13 08:21:00
>B,1.2,2023-11-13 08:22:00
>A,1.8,2023-11-13 08:23:00
>B,2.5,2023-11-13 08:24:00
>C,3.8,2023-11-13 08:25:00
>C,3.8,2023-11-13 08:41:00

  • 查看UTC与Asia/Shanghai的查询结果
Flink SQL> SET 'table.local-time-zone' = 'UTC'; 
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView4;
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| op |            window_start |              window_end |          window_rowtime |                           item |                      max_price |
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| +I | 2023-11-13 08:20:00.000 | 2023-11-13 08:30:00.000 | 2023-11-13 08:29:59.999 |                              A |                            1.8 |
| +I | 2023-11-13 08:20:00.000 | 2023-11-13 08:30:00.000 | 2023-11-13 08:29:59.999 |                              B |                            2.5 |
| +I | 2023-11-13 08:20:00.000 | 2023-11-13 08:30:00.000 | 2023-11-13 08:29:59.999 |                              C |                            3.8 |

相比在 UTC 时区下的计算结果, 在 Asia/Shanghai 时区下计算的窗口开始时间, 窗口结束时间和窗口的 rowtime 是相同的。

Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai'; 
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView4;
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| op |            window_start |              window_end |          window_rowtime |                           item |                      max_price |
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| +I | 2023-11-13 08:20:00.000 | 2023-11-13 08:30:00.000 | 2023-11-13 08:29:59.999 |                              A |                            1.8 |
| +I | 2023-11-13 08:20:00.000 | 2023-11-13 08:30:00.000 | 2023-11-13 08:29:59.999 |                              B |                            2.5 |
| +I | 2023-11-13 08:20:00.000 | 2023-11-13 08:30:00.000 | 2023-11-13 08:29:59.999 |                              C |                            3.8 |

2、TIMESTAMP_LTZ 上的事件时间属性

如果源数据中的时间为一个 epoch 时间, 通常是一个 long 值, 例如: 1618989564564 ,推荐将事件时间属性定义在 TIMESTAMP_LTZ 列上。

  • 准备测试环境,即准备表、视图和数据
Flink SQL> CREATE TABLE MyTable3 (
>  item STRING,
>  price DOUBLE,
>  ts BIGINT, -- long time value in epoch milliseconds
>  ts_ltz AS TO_TIMESTAMP_LTZ(ts, 3),
>  WATERMARK FOR ts_ltz AS ts_ltz - INTERVAL '10' SECOND
> ) WITH (
>   'connector' = 'kafka',
>   'topic' = 'alan_MyTable3',
>   'properties.bootstrap.servers' = '192.168.10.41:9092,192.168.10.42:9092,192.168.10.43:9092',
>   'properties.group.id' = 'testGroup',
>   'scan.startup.mode' = 'earliest-offset',
>   'format' = 'csv'
> );
[INFO] Execute statement succeed.

Flink SQL> CREATE VIEW MyView5 AS 
>     SELECT 
> TUMBLE_START(ts_ltz, INTERVAL '10' MINUTES) AS window_start,        
> TUMBLE_END(ts_ltz, INTERVAL '10' MINUTES) AS window_end,
> TUMBLE_ROWTIME(ts_ltz, INTERVAL '10' MINUTES) as window_rowtime,
> item,
> MAX(price) as max_price
>     FROM MyTable3
> GROUP BY TUMBLE(ts_ltz, INTERVAL '10' MINUTES), item;
[INFO] Execute statement succeed.

Flink SQL> DESC MyView5;
+----------------+----------------------------+-------+-----+--------+-----------+
|           name |                       type |  null | key | extras | watermark |
+----------------+----------------------------+-------+-----+--------+-----------+
|   window_start |               TIMESTAMP(3) | FALSE |     |        |           |
|     window_end |               TIMESTAMP(3) | FALSE |     |        |           |
| window_rowtime | TIMESTAMP_LTZ(3) *ROWTIME* |  TRUE |     |        |           |
|           item |                     STRING |  TRUE |     |        |           |
|      max_price |                     DOUBLE |  TRUE |     |        |           |
+----------------+----------------------------+-------+-----+--------+-----------+
5 rows in set

在终端执行以下命令用于写入数据到 MyTable3 :

[alanchan@server1 bin]$ kafka-console-producer.sh --broker-list server1:9092 --topic alan_MyTable3
>A,1.1,1699836971034 # The corresponding utc timestamp is 2023-11-13 08:56:xx
>B,1.2,1699837031044 # The corresponding utc timestamp is 2023-11-13 08:57:xx
>A,1.8,1699837091052 # The corresponding utc timestamp is 2023-11-13 08:58:xx
>B,2.5,1699837091052 # The corresponding utc timestamp is 2023-11-13 08:59:xx
>C,3.8,1699837211069 # The corresponding utc timestamp is 2023-11-13 09:00:xx
>C,3.8,1699837271070 # The corresponding utc timestamp is 2023-11-13 09:01:xx

  • 查看UTC与Asia/Shanghai的查询结果
Flink SQL> SET 'table.local-time-zone' = 'UTC'; 
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView5;
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| op |            window_start |              window_end |          window_rowtime |                           item |                      max_price |
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| +I | 2023-11-13 00:50:00.000 | 2023-11-13 01:00:00.000 | 2023-11-13 00:59:59.999 |                              A |                            1.8 |
| +I | 2023-11-13 00:50:00.000 | 2023-11-13 01:00:00.000 | 2023-11-13 00:59:59.999 |                              B |                            2.5 |

相比在 UTC 时区下的计算结果, 在 Asia/Shanghai 时区下计算的窗口开始时间, 窗口结束时间和窗口的 rowtime 是不同的。

Flink SQL> SET 'table.local-time-zone' = 'Asia/Shanghai'; 
[INFO] Execute statement succeed.

Flink SQL> SELECT * FROM MyView5;
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| op |            window_start |              window_end |          window_rowtime |                           item |                      max_price |
+----+-------------------------+-------------------------+-------------------------+--------------------------------+--------------------------------+
| +I | 2023-11-13 08:50:00.000 | 2023-11-13 09:00:00.000 | 2023-11-13 08:59:59.999 |                              A |                            1.8 |
| +I | 2023-11-13 08:50:00.000 | 2023-11-13 09:00:00.000 | 2023-11-13 08:59:59.999 |                              B |                            2.5 |

4、夏令时支持

Flink SQL支持在 TIMESTAMP_LTZ列上定义时间属性, 基于这一特征,Flink SQL 在窗口中使用 TIMESTAMP 和 TIMESTAMP_LTZ 类型优雅地支持了夏令时。

Flink 使用时间戳的字符格式来分割窗口并通过每条记录对应的 epoch 时间来分配窗口。 这意味着 Flink 窗口开始时间和窗口结束时间使用的是 TIMESTAMP 类型(例如: TUMBLE_START 和 TUMBLE_END), 窗口的时间属性使用的是 TIMESTAMP_LTZ 类型(例如: TUMBLE_PROCTIME, TUMBLE_ROWTIME)。

给定一个 tumble window示例, 在 Los_Angeles 时区下夏令时从 2021-03-14 02:00:00 开始:

long epoch1 = 1615708800000L; // 2021-03-14 00:00:00
long epoch2 = 1615712400000L; // 2021-03-14 01:00:00
long epoch3 = 1615716000000L; // 2021-03-14 03:00:00, 手表往前拨一小时,跳过 (2021-03-14 02:00:00)
long epoch4 = 1615719600000L; // 2021-03-14 04:00:00 

在 Los_angele 时区下, tumble window [2021-03-14 00:00:00, 2021-03-14 00:04:00] 将会收集3个小时的数据, 在其他非夏令时的时区下将会收集4个小时的数据,用户只需要在 TIMESTAMP_LTZ 列上声明时间属性即可。

Flink 的所有窗口(如 Hop window, Session window, Cumulative window)都会遵循这种方式, Flink SQL 中的所有操作都很好地支持了 TIMESTAMP_LTZ 类型,因此Flink可以非常优雅的支持夏令时。

5、Batch 模式和 Streaming 模式的区别

以下函数:

  • LOCALTIME
  • LOCALTIMESTAMP
  • CURRENT_DATE
  • CURRENT_TIME
  • CURRENT_TIMESTAMP
  • NOW()

Flink 会根据执行模式来进行不同计算,在 Streaming 模式下这些函数是每条记录都会计算一次,但在 Batch 模式下,只会在 query 开始时计算一次,所有记录都使用相同的结果。

以下时间函数无论是在 Streaming 模式还是 Batch 模式下,都会为每条记录计算一次结果:

  • CURRENT_ROW_TIMESTAMP()
  • PROCTIME()

以上,简单的介绍了Flink 中关于时区的概念,并以具体的示例进行说明。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
第一章 整体介绍 2 1.1 什么是 Table APIFlink SQL 2 1.2 需要引入的依赖 2 1.3 两种 planner(old & blink)的区别 4 第二章 API 调用 5 2.1 基本程序结构 5 2.2 创建表环境 5 2.3 在 Catalog 注册表 7 2.3.1 表(Table)的概念 7 2.3.2 连接到文件系统(Csv 格式) 7 2.3.3 连接到 Kafka 8 2.4 表的查询 9 2.4.1 Table API 的调用 9 2.4.2 SQL 查询 10 2.5 将 DataStream 转换成表 11 2.5.1 代码表达 11 2.5.2 数据类型与 Table schema 的对应 12 2.6. 创建临时视图(Temporary View) 12 2.7. 输出表 14 2.7.1 输出到文件 14 2.7.2 更新模式(Update Mode) 15 2.7.3 输出到 Kafka 16 2.7.4 输出到 ElasticSearch 16 2.7.5 输出到 MySql 17 2.8 将表转换成 DataStream 18 2.9 Query 的解释和执行 20 1. 优化查询计划 20 2. 解释成 DataStream 或者 DataSet 程序 20 第三章 流处理的特殊概念 20 3.1 流处理和关系代数(表,及 SQL)的区别 21 3.2 动态表(Dynamic Tables) 21 3.3 流式持续查询的过程 21 3.3.1 将流转换成表(Table) 22 3.3.2 持续查询(Continuous Query) 23 3.3.3 将动态表转换成流 23 3.4 时间特性 25 3.4.1 处理时间(Processing Time) 25 3.4.2 事件时间(Event Time) 27 第四章 窗口(Windows) 30 4.1 分组窗口(Group Windows) 30 4.1.1 滚动窗口 31 4.1.2 滑动窗口 32 4.1.3 会话窗口 32 4.2 Over Windows 33 1) 无界的 over window 33 2) 有界的 over window 34 4.3 SQL 窗口的定义 34 4.3.1 Group Windows 34 4.3.2 Over Windows 35 4.4 代码练习(以分组滚动窗口为例) 36 第五章 函数(Functions) 38 5.1 系统内置函数 38 5.2 UDF 40 5.2.1 注册用户自定义函数 UDF 40 5.2.2 标量函数(Scalar Functions) 40 5.2.3 表函数(Table Functions) 42 5.2.4 聚合函数(Aggregate Functions) 45 5.2.5 表聚合函数(Table Aggregate Functions) 47
### 回答1: Flink 1.14的Table APISQL教程可以在Flink官方文档找到,其包括了Table APISQL的基础概念、语法、操作符、函数等内容,还有详细的示例代码和实战案例,非常适合初学者学习和入门。另外,Flink社区也有很多优秀的博客和视频教程,可以帮助大家更深入地理解和应用Table APISQL。 ### 回答2: Flink是一个分布式计算引擎,是Apache Hadoop生态圈用于处理流式数据的一种解决方案。Flink支持表格APISQL语言,使得用户可以更加简单地实现流处理任务。而在Flink 1.14TableAPISQL引擎则得到了进一步的增强。 TableAPISQL将无需掌握Java或Scala编程语言就可以操作表格数据。TableAPI API支持Java和Scala,SQL则支持标准的SQL语言。如果你熟悉SQL语言,那么你很容易上手使用TableAPISQL引擎。 Flink TableAPISQL支持各种类型的表格操作,包括选择、过滤、分组、排序、连接等。此外,它们还支持窗口和聚合操作。这使得用户在处理流式数据时可以更加简单易懂地进行复杂的操作。 在Flink 1.14TableAPISQL引擎还提供了一系列新功能,包括: 1. 时间特征支持——TableAPISQL的数据时间戳可以通过时间特征进行定义和控制。通过时间特征,用户可以定义数据的时间属性,例如事件时间或处理时间。 2. 详细的窗口管理——当窗口的数据到期时,Flink 1.14会自动清除过期数据,避免数据量过大导致性能下降。 3. 支持更多的流数据源——在Flink 1.14TableAPISQL引擎可以直接从Kafka、Kinesis、Hive等数据源读取数据。这可以让用户更加方便地读取数据,而无需编写额外的代码。 TableAPISQL引擎对于Flink用户来说是非常重要的工具,无需掌握Java或Scala编程语言即可操作表格数据。并且在Flink 1.14,这两个工具得到了进一步的增强,包括更好的窗口管理和更多的数据源支持。因此,学习TableAPISQL引擎对于想要使用Flink进行流处理的人来说是非常有益的。 ### 回答3: Flink 1.14 TableAPISQL是一个非常好用的数据处理工具,可帮助数据分析师快速进行数据查询、聚合和处理。下面详细介绍一下Flink 1.14的TableAPISQL教程。 1. 如何配置Flink 1.14的TableAPISQL环境? 在进行Flink 1.14的TableAPISQL开发之前,需要先进行环境的配置。可以在官网下载Flink的安装包,解压后找到/bin目录下的start-cluster.sh脚本进行启动。启动之后,即可通过WebUI的页面查看Flink的运行状态。 2. TableAPI的基本操作 TableAPIFlink的一个高层次数据处理API,可以通过编写代码来进行数据的处理。TableAPI的基本操作有以下几个: (1) 创建Table,可以使用StreamTableEnvironment的fromDataStream或fromTableSource方法,将DataStream或TableSource转换成Table。 (2) Table的转换,可以使用多种转换操作,包括filter、select、orderBy、groupBy、join等。 (3) 将Table转化为DataStream,可以使用StreamTableEnvironment的toDataStream方法。 3. SQL的基本操作 SQLFlink提供的一种快速数据处理方式,用户只需要编写SQL语句即可完成数据处理。SQL的基本操作有以下几个: (1) 注册Table,可以使用StreamTableEnvironment的registerTable或registerTableSource方法,将TableTableSource注册到环境。 (2) 执行SQL,可以使用StreamTableEnvironment的executeSql方法,执行SQL语句并返回结果。 (3) 将结果转换为DataStream,可以使用StreamTableEnvironment的toDataStream方法。 4. 如何优化Flink 1.14的TableAPISQL的执行效率? 在进行TableAPISQL开发时,为了保证其执行效率,需要注意以下几点: (1) 避免使用复杂的JOIN操作,可以使用Broadcast和TableFunction等方式来避免JOIN操作。 (2) 注意Table的Schema定义,Schema的设计合理与否直接影响SQL性能。 (3) 避免使用无限制的聚合操作,可以进行分批次聚合来避免。 总的来说,Flink 1.14的TableAPISQL是非常强大的数据处理工具,能够帮助开发者快速高效的进行数据处理。上述内容是入门级别的教程,如果想要更深入的了解,可以参考官方文档进行学习。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一瓢一瓢的饮 alanchanchn

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

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

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

打赏作者

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

抵扣说明:

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

余额充值