时态表表示一个可变表上(参数化)视图的概念,该视图返回表在特定时间点的内容。
变更表可以是跟踪变更的变更历史表(如数据库变更日志),也可以是具体化变更的变更维度表(如数据库表)。
对于更改历史表,Flink可以跟踪更改,并允许在查询中的某个时间点访问表的内容。在Flink中,这种表由一个时态表函数表示。
对于更改维度表,Flink允许在查询中的处理时间访问表的内容。在Flink中,这种表由一个时态表表示。
一、Motivation(动机)
- 1、与不断变化的历史表相关联(Correlate with a changing history table)
假设我们有下表RatesHistory.
SELECT * FROM RatesHistory;
rowtime currency rate
======= ======== ======
09:00 US Dollar 102
09:00 Euro 114
09:00 Yen 1
10:45 Euro 116
11:15 Euro 119
11:49 Pounds 108
汇率表是一个不断增长的日元汇率附加表(汇率为1)。例如,欧元对日元的汇率从09:00到10:45为114。从10:45到11:15是116。
考虑到我们希望在10:58时输出所有当前速率,我们需要以下SQL查询来计算结果表:
SELECT *
FROM RatesHistory AS r
WHERE r.rowtime = (
SELECT MAX(rowtime)
FROM RatesHistory AS r2
WHERE r2.currency = r.currency
AND r2.rowtime <= TIME '10:58');
相关子查询确定对应的货币的最大时间低于或等于期望的时间。外部查询列出具有最大时间戳的速率。
下表显示了这种计算的结果。在我们的例子中,10:45时欧元的更新被考虑在内,但是11:15时欧元的更新和10:58时表格版本中不考虑英镑的新条目。
rowtime currency rate
======= ======== ======
09:00 US Dollar 102
09:00 Yen 1
10:45 Euro 116
时态表的概念旨在简化此类查询,加快它们的执行速度,并减少Flink的状态使用。临时表是仅追加表上的参数化视图,它将仅追加表的行解释为表的变更日志,并在特定时间点提供该表的版本。将append only表解释为变更日志需要指定主键属性和时间戳属性。主键确定覆盖哪些行,时间戳确定行有效的时间。
在上面的示例中,currency将是RatesHistory表的主键,rowtime将是timestamp属性。
在Flink中,这由一个时态表函数表示。
- 2、与更改维度表关联(Correlate with a changing dimension table)
另一方面,一些用例需要连接一个不断变化的维度表,这个维度表是一个外部数据库表。
假设latest rate s是一个表(例如,存储在中),它以最新的速率具体化。后来者是物化的历史资本家。那么10:58的LatestRates表的内容将是:
10:58> SELECT * FROM LatestRates;
currency rate
======== ======
US Dollar 102
Yen 1
Euro 116
12:00时LatestRates表的内容为:
12:00> SELECT * FROM LatestRates;
currency rate
======== ======
US Dollar 102
Yen 1
Euro 119
Pounds 108
在Flink中,这由一个时态表表示。
二、时态表函数(Temporal Table Function)
为了访问临时表中的数据,必须传递一个时间属性,该属性确定将返回的表的版本。Flink使用表函数的SQL语法来提供一种表达它的方法。
定义后,临时表函数接受单个时间参数timeAttribute并返回一组行。此集合包含相对于给定时间属性的所有现有主键的行的最新版本。
假设我们基于RatesHistory表定义了一个时态表函数Rates(timeAttribute),我们可以通过以下方式查询这样一个函数:
SELECT * FROM Rates('10:15');
rowtime currency rate
======= ======== ======
09:00 US Dollar 102
09:00 Euro 114
09:00 Yen 1
SELECT * FROM Rates('11:00');
rowtime currency rate
======= ======== ======
09:00 US Dollar 102
10:45 Euro 116
09:00 Yen 1
每个对Rates(timeAttribute)的查询都将返回给定timeAttribute的Rates状态。
注意:目前,Flink不支持使用常量time属性参数直接查询时态表函数。目前,时态表函数只能在连接中使用。上面的示例用于提供有关函数速率(timeAttribute)返回值的直观信息。
有关如何与时态表联接的详细信息,请参见关于连续查询联接的页面。
- 定义时太表函数(Defining Temporal Table Function)
下面的代码片段演示如何从只追加的表创建临时表函数。
import org.apache.flink.table.functions.TemporalTableFunction;
(...)
// Get the stream and table environments.
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment tEnv = StreamTableEnvironment.create(env);
// Provide a static data set of the rates history table.
List<Tuple2<String, Long>> ratesHistoryData = new ArrayList<>();
ratesHistoryData.add(Tuple2.of("US Dollar", 102L));
ratesHistoryData.add(Tuple2.of("Euro", 114L));
ratesHistoryData.add(Tuple2.of("Yen", 1L));
ratesHistoryData.add(Tuple2.of("Euro", 116L));
ratesHistoryData.add(Tuple2.of("Euro", 119L));
// Create and register an example table using above data set.
// In the real setup, you should replace this with your own table.
DataStream<Tuple2<String, Long>> ratesHistoryStream = env.fromCollection(ratesHistoryData);
Table ratesHistory = tEnv.fromDataStream(ratesHistoryStream, "r_currency, r_rate, r_proctime.proctime");
tEnv.registerTable("RatesHistory", ratesHistory);
// Create and register a temporal table function.
// Define "r_proctime" as the time attribute and "r_currency" as the primary key.
TemporalTableFunction rates = ratesHistory.createTemporalTableFunction("r_proctime", "r_currency"); // <==== (1)
tEnv.registerFunction("Rates", rates);
第(1)行创建一个rates临时表函数,它允许我们使用table API中的函数rates。
第(2)行在我们的表环境中的名称Rates下注册了这个函数,这允许我们在SQL中使用Rates函数。
三、时间表(Temporal Table)
注意:这只在Blink planner中支持。
为了访问临时表中的数据,当前必须使用LookupableTableSource定义一个表源。Flink使用FOR SYSTEM TIME-AS-of的SQL语法来查询时态表,这是SQL:2011中提出的。
假设我们定义了一个名为LatestRates的时态表,我们可以通过以下方式查询这样一个表:
SELECT * FROM LatestRates FOR SYSTEM_TIME AS OF TIME '10:15';
currency rate
======== ======
US Dollar 102
Euro 114
Yen 1
SELECT * FROM LatestRates FOR SYSTEM_TIME AS OF TIME '11:00';
currency rate
======== ======
US Dollar 102
Euro 116
Yen 1
注意:目前,Flink不支持在时间不变的情况下直接查询时态表。目前,时态表只能用于连接。上面的示例用于提供有关时态表延迟返回的内容的直觉。
有关如何与时态表联接的详细信息,请参见关于连续查询联接的页面。
- 定义时态表(Defining Temporal Table)
// Get the stream and table environments.
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment tEnv = TableEnvironment.getTableEnvironment(env);
// Create an HBaseTableSource as a temporal table which implements LookableTableSource
// In the real setup, you should replace this with your own table.
HBaseTableSource rates = new HBaseTableSource(conf, "Rates");
rates.setRowKey("currency", String.class); // currency as the primary key
rates.addColumn("fam1", "rate", Double.class);
// register the temporal table into environment, then we can query it in sql
tEnv.registerTableSource("Rates", rates);
官网地址:Temporal Tables