拉鏈表是數據倉庫設計中用來處理數據變化的一種技術,它允許保存歷史數據,記錄一個事物從開始到當前狀態的所有變化信息,可以反映任意時間點數據的狀態。本文將為您介紹基于MaxCompute引擎在DataWorks上實現拉鏈表ETL的案例。
前提條件
已創建DataWorks工作空間,詳情請參見創建工作空間。
已創建MaxCompute數據源并綁定至工作空間,詳情請參見創建MaxCompute數據源并綁定至工作空間。
注意事項
本案例通過命令建表,在實際開發中,您可通過DataWorks可視化功能創建,詳情請參見創建并使用MaxCompute表。
本案例中的數據開發部分任務,也可以通過ETL工作流模板一鍵導入。在導入模板后,您可以前往目標工作空間,并自行完成任務運維等后續操作。
僅空間管理員角色可導入ETL模板至目標工作空間,為賬號授權空間管理員角色詳情請參見空間級模塊權限管控。
導入ETL工作流模板,詳情請參見ETL工作流快速體驗。
ETL工作流模板快捷入口,請點擊拉鏈表實現。
適用場景
在設計數據倉庫的數據模型時,拉鏈存儲技術可作為一種解決方案,滿足以下需求:
數據量較大。
表中的部分字段被更新。
例如,用戶的地址、產品的描述信息、訂單的狀態和手機號碼等。
需要查看某一個時間點或時間段的歷史快照信息。
例如,查看某一個訂單在某一個歷史時間點的狀態,或查看某一個用戶在過去某段時間內更新過幾次等。
變化的比例不大或頻率不高。
假設總共有1000萬個會員,且每天新增和發生變化的會員只有10萬左右,如果每天都在表中保留一份全量,那么每次全量中會保存很多不變的信息,極大地浪費了存儲資源。
關鍵字段介紹
拉鏈表通常包含以下幾個關鍵字段:
字段 | 描述 |
主鍵 | 唯一標識每一行數據。 |
業務主鍵 | 唯一標識實體的主鍵。例如,會員ID等。 |
屬性字段 | 需要追蹤變化的實體屬性。例如,會員昵稱、會員手機號等。 |
有效開始日期 | 數據版本的有效開始時間。 |
有效結束日期 | 數據版本的有效結束時間。通常用一個極大值“9999-12-31”表示當前數據有效。 |
狀態標識符 | 標識是否為最新版本。 |
版本 | 標識相同業務主鍵的不同歷史版本號。 |
本文主要展示拉鏈表的實現案例,關于設計部分不在這里過多展開。
案例介紹
數據表設計,本案例共設計2張數據表。
交易下單源表:ods_order_d,用于存放業務庫同步過來的每日增量數據。包含如下兩個字段:
id:業務主鍵訂單ID。
status:追蹤變化的訂單狀態。
交易下單事實表(拉鏈表):dwd_order,用于拉鏈存儲全量有效和失效的數據。包含如下四個字段:
id:業務主鍵訂單ID。
status:追蹤變化的訂單狀態。
start_date:有效開始日期。
end_date:有效結束時間。
拉鏈表實現邏輯。
本案例將使用拉鏈表記錄電商訂單從開始到當前狀態(創建/支付/完成)的所有變化信息,拉鏈表的加載邏輯詳情請參見:拉鏈表數據加載邏輯。
任務開發:準備工作
進入數據開發頁面。
登錄DataWorks控制臺,切換至目標地域后,單擊左側導航欄的 ,在下拉框中選擇對應工作空間后單擊進入數據開發。
創建業務流程。
鼠標懸停至圖標,單擊新建業務流程。
在新建業務流程對話框中,輸入業務名稱和描述。本案例業務流程名為體驗案例_拉鏈表的實現。
單擊新建。
新建節點。
在左側目錄樹中,雙擊步驟2中創建的業務流程名稱,進入業務流程面板,并通過拖拽組件以及拉線的方式在業務流程畫布中編排整個流程。
本案例中會使用到兩個類型節點:虛擬節點和開發ODPS SQL任務。
虛擬節點將作為整個拉鏈表實現的起始節點,用于管理整個業務流程;
ODPS SQL節點用于執行SQL任務,通過使用SQL語法實現拉鏈表數據加載。
任務流程圖預覽。
本案例預計將創建以下業務流程。其中,為便于快速辨別每一個任務加工邏輯,本案例使用節點組功能對節點進行分組,節點代碼請參照后續步驟。
任務開發:增量表數據準備
在數據準備環節,需要創建兩個類型節點:
創建虛擬節點:
拉鏈表實現說明
,用于流程管理和介紹的作用。創建ODPS SQL節點:
ods_order_di
,用于產出交易下單源表數據。
節點間的依賴關系,如下圖所示:
ods_order_di
表數據:交易下單源表,包含業務主鍵訂單ID和需要追蹤變化的訂單狀態status字段,用于存放每日新增交易下單數據。
在
ods_order_di
節點編輯頁面,需要將以下ods_order.csv測試數據,存儲在ods_order_di交易下單源表中。ods_order.csv 測試數據。
id,gmt_create,gmt_modified,status,pt 210001,2023-10-04,2023-10-04,創建,2023-10-04 210002,2023-10-04,2023-10-04,創建,2023-10-04 210001,2023-10-04,2023-10-05,支付,2023-10-05 210003,2023-10-05,2023-10-05,創建,2023-10-05 210004,2023-10-05,2023-10-05,創建,2023-10-05 210001,2023-10-04,2023-10-06,完成,2023-10-06 210002,2023-10-04,2023-10-06,支付,2023-10-06 210004,2023-10-05,2023-10-06,支付,2023-10-06 210005,2023-10-06,2023-10-06,創建,2023-10-06
在插入測試數據的時候,需要按照對應的分區(pt)進行補充,操作如下:
-- 補充說明:由于案例測試需要,我們將3天的每日新增數據一次性分別插入分區'2023-10-04、2023-10-05、2023-10-06', -- 在實際業務場景中,一般每日更新當前業務日期分區,僅需將分區日期設置成調度參數變量即可。 INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-04') VALUES (210001,DATE'2023-10-04',DATE'2023-10-04','創建') ,(210002,DATE'2023-10-04',DATE'2023-10-04','創建') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-05') VALUES (210001,DATE'2023-10-04',DATE'2023-10-05','支付') ,(210003,DATE'2023-10-05',DATE'2023-10-05','創建') ,(210004,DATE'2023-10-05',DATE'2023-10-05','創建') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-06') VALUES (210001,DATE'2023-10-04',DATE'2023-10-06','完成') ,(210002,DATE'2023-10-04',DATE'2023-10-06','支付') ,(210004,DATE'2023-10-05',DATE'2023-10-06','支付') ,(210005,DATE'2023-10-06',DATE'2023-10-06','創建')
完整代碼,如下示例:
-- 1. 創建ods_order_di訂單源表,存放每日新增交易下單數據。 -- 補充說明:為了便于理解,我們約定案例中的“訂單創建時間、修改時間字段”粒度到天級別,且默認一個訂單一天僅執行一次操作; -- 實際業務中一般時間字段粒度更細,并且一天可能有多次操作。 CREATE TABLE IF NOT EXISTS ods_order_di ( id BIGINT COMMENT '訂單ID' ,gmt_create DATE COMMENT '創建時間,格式為yyyy-mm-dd' ,gmt_modified DATE COMMENT '更新時間,格式為yyyy-mm-dd' ,`status` STRING COMMENT '狀態' ) COMMENT '交易下單源表' PARTITIONED BY ( pt STRING COMMENT '日期,格式為yyyy-mm-dd' ) LIFECYCLE 7 ; -- 2. 初始化歷史交易下單新增數據。 -- 補充說明:由于案例測試需要,我們將3天的每日新增數據一次性分別插入分區'2023-10-04、2023-10-05、2023-10-06', -- 在實際業務場景中,一般每日更新當前業務日期分區,僅需將分區日期設置成調度參數變量即可。 INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-04') VALUES (210001,DATE'2023-10-04',DATE'2023-10-04','創建') ,(210002,DATE'2023-10-04',DATE'2023-10-04','創建') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-05') VALUES (210001,DATE'2023-10-04',DATE'2023-10-05','支付') ,(210003,DATE'2023-10-05',DATE'2023-10-05','創建') ,(210004,DATE'2023-10-05',DATE'2023-10-05','創建') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-06') VALUES (210001,DATE'2023-10-04',DATE'2023-10-06','完成') ,(210002,DATE'2023-10-04',DATE'2023-10-06','支付') ,(210004,DATE'2023-10-05',DATE'2023-10-06','支付') ,(210005,DATE'2023-10-06',DATE'2023-10-06','創建')
任務開發:拉鏈表的實現
創建ODPS SQL節點:
dwd_order
,用于產出交易下單事實明細表數據。節點間的依賴關系,如下圖所示:
dwd_order
表數據:交易下單事實明細表(拉鏈表),用于存放全量有效數據和全量失效數據。包含有效開始日期start_date、有效結束時間end_date、業務主鍵ID和追蹤訂單狀態變化的status字段。
在
dwd_order
節點編輯頁面,輸入如下示例代碼:-- 1. 創建交易下單事實明細表,存放全量數據(拉鏈存儲)。 -- 補充說明:拉鏈表增加記錄生命周期的字段start_date(生效日期)、end_date(失效日期),當end_date為極大值'9999-12-31' -- 時表示數據有效。 CREATE TABLE IF NOT EXISTS dwd_order ( ID BIGINT COMMENT '訂單ID' ,gmt_create DATE COMMENT '創建時間,格式為yyyy-mm-dd' ,gmt_modified DATE COMMENT '更新時間,格式為yyyy-mm-dd' ,`status` STRING COMMENT '狀態' ,start_date DATE COMMENT '生效日期,格式為yyyy-mm-dd' ,end_date DATE COMMENT '失效日期,格式為yyyy-mm-dd,9999-12-31表示有效' ) COMMENT '交易下單事實明細表(拉鏈表)' ; -- 2. 拉鏈存儲的實現邏輯:業務日期當日ods_order_di新增或更新的所有數據插入dwd_order狀態為有效數據、dwd_order中 -- 有更新過的有效數據修改成失效數據。 INSERT OVERWRITE TABLE dwd_order SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM ( SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date -- 2.3 支持重跑:使用開窗函數,按id,gmt_create,gmt_modified,`status`分發,按end_date reducer內降序排序,僅取第一條數據。 ,ROW_NUMBER() OVER (DISTRIBUTE BY id,gmt_create,gmt_modified,`status` SORT BY end_date DESC ) AS row_num FROM ( -- 2.1 當日失效數據:dwd_order中有被更新過的有效數據修改成失效數據。 SELECT a.id AS id ,a.gmt_create AS gmt_create ,a.gmt_modified AS gmt_modified ,a.`status` AS `status` ,a.start_date AS start_date ,CASE WHEN b.id IS NOT NULL -- AND CAST(a.end_date AS STRING) > '${biz_date}' THEN DATE'${biz_date}' 這里再考慮下用哪個合適 AND CAST(a.end_date AS STRING) == '9999-12-31' THEN DATE'${biz_date}' ELSE a.end_date END AS end_date -- 2.4 調度依賴補充說明:由于當日dwd_order表數據計算依賴于自身昨日數據產出,所以我們在節點「調度配置」-「跨周期依賴」中配置了依賴「本節點」。 FROM dwd_order AS a LEFT JOIN ( SELECT id ,gmt_create ,gmt_modified ,`status` FROM ods_order_di WHERE pt == '${biz_date}' ) b ON a.id == b.id UNION ALL -- 2.2 當日新增或更新的有效數據:業務日期當日ods_order_di新增或更新的所有數據插入dwd_order狀態為有效數據。 SELECT id ,gmt_create ,gmt_modified ,`status` ,DATE'${biz_date}' AS start_date ,DATE'9999-12-31' AS end_date FROM ods_order_di WHERE pt == '${biz_date}' ) ) with_row_num_tb -- 支持重跑 WHERE row_num == 1 ;
調度配置,核心配置要點如下,其他參數保持默認即可。
調度參數:在
中,點擊加載代碼中的參數自動生成的參數配置結果,參數值中輸入$[yyyy-mm-dd-1]
,更多關于調度參數的配置說明,請參見調度參數支持的格式。說明您也可以單擊用表達式定義,使用手動輸入的方式添加調度參數
biz_date=$[yyyy-mm-dd-1]
配置跨周期依賴。由于dwd_order表的當天數據處理依賴于自身前一日的數據產出,為了確保數據處理的正確性和連續性。
在
中勾選本節點的設置自依賴操作。通過配置自依賴,可以保障只有在上一周期的數據成功處理后,才會進行當前周期的數據加載,從而保障了數據處理流程的順利進行。
拉鏈表數據加載邏輯
業務日期當日dwd_order表中,有被更新過的有效數據“修改”成失效數據;
業務日期當日ods_order_di表中,新增的所有數據插入dwd_order表中,狀態為有效數據。
以業務日期10.5日拉鏈表數據加載為例,如下圖所示,具體步驟如下:
原始數據:在10.4日的拉鏈表記錄中,存在一條訂單ID為“210001”,其狀態為“創建”。
狀態變更:到10.5日該訂單狀態被更新為“支付”。
數據對比邏輯:
將10.4日拉鏈表歷史全量有效數據和增量表“2023-10-05”分區新增的數據關聯查詢。
更新狀態判斷:如果ID為“210001”的訂單在10.4日拉鏈表中存在,且end_date為“9999-12-31”,說明該記錄有效,同時該訂單出現在增量表“2023-10-05”的分區中,則說明狀態已更新。
更新處理:
需要將原拉鏈表中記錄end_date:“9999-12-31”“修改”為當前業務日期“2023-10-05”。
如果該訂單ID未出現在增量表“2023-10-05”的分區中,則說明無更新,維持原記錄不變。
數據覆蓋:
完成上述步驟后,將拉鏈表中處理好的歷史數據與增量表中新增的所有數據,一同覆蓋寫回拉鏈表中,最終產出10.5日拉鏈表數據。
任務開發:拉鏈表的使用
本階段需要創建一個ODPS SQL節點,依賴上述所有任務:
拉鏈表查詢
節點。
節點間的依賴關系,如圖所示:
表定義:通過上述步驟已經完成了拉鏈表數據加載,通過創建查詢節點,編寫SQL查詢語句,實現拉鏈存儲結果的查詢。
在
拉鏈表查詢
節點編輯頁面,輸入如下示例代碼:-- 1. 拉鏈表使用 -- 1.1 我們僅需查詢dwd_order表中end_date=9999-12-31的記錄就可以得到全量最新狀態的有效數據。 SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM dwd_order WHERE end_date == DATE'9999-12-31' ORDER BY id DESC LIMIT 100 ; -- 1.2 我們僅需查詢dwd_order表中指定的訂單id并按end_date排序的記錄就可以得到該訂單所有的歷史快照。 SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM dwd_order WHERE id == 210001 ORDER BY end_date DESC LIMIT 100 ; -- 1.3 查詢dwd_order表中全量數據,并按訂單id,end_date降序排序。 SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM dwd_order ORDER BY id,end_date DESC LIMIT 100 ;
運行業務流程
由于上述的案例測試中,我們將3天的每日新增數據一次性分別插入指定分區"2023-10-04、2023-10-05、2023-10-06",所以需要在生產環境執行補數據操作,實現業務數據回刷操作。運維中心補數據操作如下。
提交任務。
單擊工具欄中的圖表。
在提交對話框中,選中需要提交的節點,輸入變更描述。
單擊確認,在對話框中出現操作完成,說明任務提交成功。
如果您使用的是標準模式的工作空間,提交成功后,請單擊右上方的發布。具體操作請參見發布任務。
進入運維中心。
任務發布成功后,單擊右上角的運維中心。
您也可以進入業務流程(體驗案例_拉鏈表的實現)的編輯頁面,單擊工具欄中的前往運維,進入運維中心頁面。
周期任務執行補數據操作。
在左側導航欄,單擊
,進入周期任務頁面,單擊業務流程(體驗案例_拉鏈表的實現)的起始根節點拉鏈表實現說明
。右鍵單擊
拉鏈表實現說明
節點,選擇 。在補數據對話框中,選擇業務日期為2023-10-04~2023-10-06,在選擇需要補數據的節點中勾選所有節點,單擊確定,自動跳轉至補數據實例頁面。
單擊刷新,直至SQL任務全部運行成功即可。
結果查詢
在運維中心運行完所有SQL任務后,您可以在日志中查看運行結果:
在補數據示例頁面的實例列表中,單擊拉鏈表查詢節點操作列的DAG圖,點擊查看日志。
進入拉鏈表查詢的運行日志詳情頁面,在
中,可以查看到運行的結果。
若在運維中心運行完所有SQL任務,您也可以回到數據開發(DataStudio)通過單獨運行拉鏈表查詢
節點,運行查看拉鏈存儲結果。
附錄:使用ETL工作流模板
DataWorks ETL工作流模板已內置該案例,您直接導入本案例相關代碼,具體操作如下:
登錄DataWorks控制臺,點擊左側導航欄的 ,進入ETL工作流模板頁面。
在ETL工作流模板頁面選擇拉鏈表實現業務流程,單擊查看詳情進入模板頁面,點擊載入模板。
在載入模板對話框中,選擇對應的工作空間,并在MaxCompute配置中選擇在數據源名稱下拉列表中選擇數據源,點擊確認載入模板。
資源釋放
若您在案例測試完成之后,想要清理與釋放當前案例生成的資源,您可參考以下文檔處理:
刪除表:批量刪除MaxCompute表。
下線任務:下線任務。
相關文檔
了解虛擬節點相關操作,詳情請參見:虛擬節點。
了解MaxCompute節點的ODPS SQL節點,詳情請參見:創建并管理MaxCompute節點。
了解更多開發ODPS SQL任務,詳情請參見:開發ODPS SQL任務。
了解更多運維中心的周期任務調度,詳情請參見:周期任務基本運維操作。