Flink中的臨時表 Temporal Tables

臨時表 Temporal Tables

翻譯自flink官方文檔:https://ci.apache.org/projects/flink/flink-docs-release-1.10/dev/table/streaming/temporal_tables.html#top

臨時表表示一個可變表上(參數化)視圖的概念,該視圖返回表在特定時間點的內容。

可變表可以是跟蹤變更的變更歷史表(如數據庫變更日誌),也可以是具體化變更的可變維度表(如數據庫表)。

對於變更歷史表,Flink可以跟蹤更改,並允許在查詢中以某個時間點爲依據訪問表的內容。在Flink中,這種表由一個臨時表函數(Temporal Table Function)表示。

對於可變維度表,Flink允許在查詢中以處理時間(processing time)爲依據訪問表的內容。在Flink中,這種表由一個臨時表(Temporal Table)表示。

使用臨時表的動機 Motivation

關聯變更記錄表 Correlate with a changing history table

假設有如下,匯率變更歷史記錄表:

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

RatesHistory表示不斷增長的僅追加的日元匯率的表。
例如,從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時歐元的更新,但是10:58時表的版本中未考慮11:15時歐元的更新和新的英鎊輸入。

rowtime currency   rate
======= ======== ======
09:00   US Dollar   102
09:00   Yen           1
10:45   Euro        116

臨時表的概念旨在簡化此類查詢,加快它們的執行速度,並減少Flink的狀態使用。臨時表是僅追加(append-only)表上的參數化視圖,它將append-only表的行解釋爲表的變更日誌,並在特定時間點提供該表的特定版本。將append- only表解釋爲變更日誌需要指定主鍵屬性和時間戳屬性。主鍵確定覆蓋哪些行,時間戳確定行有效的時間。

在上面的示例中,currency將是RatesHistory表的主鍵,rowtime將是timestamp屬性。
在Flink中,這由一個臨時表函數(Temporal Table Function)表示。

關聯可變維度表 Correlate with a changing dimension table

另一方面,一些用例需要連接一個不斷變化的維度表,這個維度表是一個外部數據庫表。

假設LatestRates是一個以最新匯率具體化的表格。 LatestRates是歷史匯率的具體化。 那麼在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)表示。

臨時表函數 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不支持使用常量時間屬性參數直接查詢臨時表函數。同時,臨時表函數只能在join中使用。 上面的示例僅用於提供有關Rates(timeAttribute)函數返回值的直觀信息。

另請參閱有關用於連續查詢的聯接( joins for continuous queries)的頁面,以獲取有關如何與臨時表聯接的更多信息。

定義臨時表函數 Defining Temporal Table Function

以下代碼段說明了如何從僅追加(append-only)表中創建臨時表函數。

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.createTemporaryView("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);      // <==== (2)


第(1)行創建了一個匯率臨時表函數,該函數使我們能夠在Table API中使用函數。

第(2)行在表環境中以Rates名稱註冊了該函數,這使我們可以在SQL中使用Rates函數。

臨時表 Temporal Table

注意:Temporal Table 僅適用於Blink Planner。

爲了訪問臨時表中的數據,當前必須使用LookupableTableSource定義一個TableSource。 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不支持以固定時間直接查詢臨時表。同時,臨時表只能在聯接中使用。 上面的示例僅用於提供有關臨時表LatestRates返回的直觀信息。

另請參閱有關用於連續查詢的聯接的頁面,以獲取有關如何與臨時表聯接的更多信息。

定義臨時表 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);

另請參閱有關如何定義LookupableTableSource的頁面。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章