![]() | 博主歷時三年精心創作的《大數據平臺架構與原型實現:數據中臺建設實戰》一書現已由知名IT圖書品牌電子工業出版社博文視點出版發行,點擊《重磅推薦:建大數據平臺太難了!給我發個工程原型吧!》了解圖書詳情,京東購書鏈接:https://item.jd.com/12677623.html,掃描左側二維碼進入京東手機購書頁面。 |
根據 [ 官方文檔 ] 所述,在 Flink 中,時態表和動態表是一個概念,只是強調的側重點不同。Flink 流上的表都是動態的,也就是一直在變化,所以被稱為動態表,因為動態表都會隨時間發生變化,所以也被叫作了 “時態表”。而根據能否 trace (追蹤) 一張時態表的變化歷史,時態表會細分成:版本表 和 普通表 兩種,區別就是:版本表可以追溯歷史,而普通表只保存當前最新狀態的數據。
Flink 官方文檔中說:定義了主鍵約束和事件時間屬性(通過 WATERMARK 關鍵字標識)的表就是版本表,并且舉例說:數據庫的 changelog 數據(CDC數據)就可以定義成版本表。這里不要產生錯誤的理解,不是說只有數據庫的 changelog 數據才支持定義成版本表,而是說數據庫的 changelog 型數據是版本表的一種典型數據,因為它必定包含記錄的主鍵和一個標記操作執行的時間戳。
以下是援引自官方文檔中的一張版本表的定義:
-- 定義一張版本表
-- 只有同時定義了主鍵和事件時間字段的表才是一張版本表
-- 通過 CDC 技術從數據庫采集的 changelog 數據是構成版本表的數據“典型”數據
-- 但并不是說:版本表的數據一定是 changelog 型的數據,只要滿足有主鍵和事件時間字段數據,就可以定義為版本表
CREATE TABLE product_changelog (product_id STRING,product_name STRING,product_price DECIMAL(10, 4),update_time TIMESTAMP(3) METADATA FROM 'value.source.timestamp' VIRTUAL,PRIMARY KEY(product_id) NOT ENFORCED, -- 版本表特征(1) 定義主鍵WATERMARK FOR update_time AS update_time -- 版本表特征(2) 定義事件時間字段(通過 watermark 定義事件時間)
) WITH ('connector' = 'kafka','topic' = 'products','scan.startup.mode' = 'earliest-offset','properties.bootstrap.servers' = 'localhost:9092','value.format' = 'debezium-json'
);
實際上,Flink 的版本表條件和定義一張 Hudi 表所必須指定的兩項配置:hoodie.datasource.write.recordkey.field 和 precombine.field 在性質上是一樣的:如果你想區別同一條記錄的不同版本,就得需要同時指定記錄的唯一標識(即主鍵)和當出現相同主鍵記錄時的版本號(即記錄的時間戳),本質上,這是保證記錄版本可回溯的兩個必要條件,所以才會有 Flink 版本表與 Hudi 表之間的這種“神似”狀況。
以下是對四個概念的梳理:
時態表 <=> 動態表├── 版本表:可追溯歷史版本,只有定義了:主鍵和事件時間屬性(通過 watermark 定義) 的表才可以成為一張版本表,│ 反過來說:數據本身必須包含主鍵字段和一個標記記錄生成或更新的時間戳字段才能被定義成 Flink 上的版本表。│ 由于版本表有這兩項約束條件,能構成版本表的數據往往是 changelog 型數據,典型代表是數據庫的 CDC 數據;└── 普通表:只保存當前最新狀態數據,就是只能拿到當前最新快照
普通表并不會特別拿來強調,只是用于和版本表這個概念做對比的,真正被特別拿來強調的是版本表,而經常與版本表放在一起提及的就是“Temporal join“,但是這里又有一點概念上的一點小小的錯位:“Temporal join“ 指得不是時態表 Join,而是時態表中的版本表 Join,好像提及 時態表 / Temporal Table 時默認指的就是 版本表。應該是 Flink 在歷史上對這些概念沒有進行明確的定義,各種混用導致了概念上的一些輕微的混淆。