[Hadoop Ecosystem] 理解 Sqoop export 的各種情境

Ticy Yang
5 min readDec 16, 2023

--

在 Hadoop 生態系中,最常被討論的是 HDFS、Hive、Spark 等,Sqoop 算是比較少被提及,實務上卻經常被大量使用。它的概念相對簡單,但一些參數的搭配、調整還是有一些細節要注意

Sqoop 相關的教學、文章大多集中在 import。Sqoop import,基本上就是將關聯式資料庫 (以下簡稱 RDB) 的資料傳輸到 Hadoop,那反過來呢? 從 Hadoop 傳資料到 RDB 要用什麼?

沒錯! 就是 Sqoop export

剛好最近工作上有個案子要用到 export 的功能,啃了官方文件後發現,最有可能搞混的就是從 update-mode 和 update-key 這 2 個參數組合而成的各種使用情境,用一張我嘔心瀝血 (誤) 整理的圖來說明:

以下從我理出這些情境的過程,列舉其中幾種來說明,不會全部介紹,往下看就會慢慢了解為什麼 (如果想快速查找適用的選項,可直接點擊跳到「什麼時候用哪個?」這一段)

情境一:目標table有PK,更新現有的資料,不要插入新資料
情境二:目標table有PK,更新現有的資料,也要插入新資料
情境三:目標table沒有PK,不要更新現有的資料,要插入新資料
情境四:目標table沒有PK,更新現有的資料,也要插入新資料
什麼時候用哪個?
補充:Sqoop eval操作Oracle DB遇到的小問題

情境一:目標 table 有 PK,更新現有的資料,不要插入新資料

從上圖中每個分支點一個一個來看,記得目標 table 是在 RDB,所以會有設不設 PK 的問題,這裡就假設有 PK,所以第一個分支會走上面那條路

update-mode 要選哪一個? 關鍵在於「若有新的資料不要加進去」,所以不允許它加入新資料,選擇「udpateonly」,也就是上面那條路

最後,要不要指定 update-key? 目標 table 設 PK 的意義就是避免重複並能識別,要對目標 table 進行更新,將 update-key 指定為 PK 欄位,才能正確的比對並 update

--update-mode "udpateonly" \
--update-key "<pk_column_name>" \

由於「updateonly」是預設的 update-mode,不寫也是可以的,不過個人習慣是寫出來以便快速區分

注意如果是複合 PK,例如 「id + name」,用逗號隔開:

--update-key "id,name"

情境二:目標 table 有 PK,更新現有的資料,也要插入新資料

注意,若有新的資料加進去

與情境一不同的是在選擇 update-mode 的時候,要選 「allowinsert」,才能插入新資料。一樣要指定 update-key,才能比對到原本不存在的紀錄進行 insert

這個情境相當於 upsert,有的資料就 update,沒有的就 insert

--update-mode "allowinsert" \
--update-key "<pk_column_name>" \

情境三:目標 table 沒有 PK,不要更新現有的資料,要插入新資料

換個口味,目標 table 沒有 PK 的情況,不更新現有資料又要插入新資料,也就是追加 insert,換句話說就是將指定的 Hadoop 的資料全部倒進目標 table

第一個分支當然就選下面那條路囉,update-mode 呢? 「udpateonly」和「allowinsert」都可以! 兩者後續都有可以實現目標的選項

update-key 要不要指定? 答案是不用! 因為不要動到現有的資料,不需要進行任何比對,不設這個參數

情境四:目標 table 沒有 PK,更新現有的資料,也要插入新資料

和情境二有點像,也是 upsert。要插入新資料,所以 update-mode 要選「 allowinsert」

不同於目標 table 有 PK 的情況,update-key 可以自由指定,不過通常在設計 table 的時候應該不會是這麼 free 的情況,這個就斟酌使用了

什麼時候用哪個?

上面那張圖是從參數的組合出發到達成的結果,以下改成目標導向,重新整理過後應該清楚多了:

特別注意,僅 insert 且目標 table 有 PK 時,你的目的應該是有一批全新的資料要插入,只要可以確定這是全新的資料,不會引發任何的 PK 衝突就沒問題。

如果在 PK 欄位的值有重複的話會引發 PK 衝突,這時候 Sqoop 會卡住,顯示為 Map 100%,然後就沒有然後了,完全不會動,只能 Ctrl + C 直接取消
(需要注意的是,也要到目標 RDB 解決 table lock,解決的方式這裡就不贅述)

簡單暴力的做法,可以用 upsert 的方式,現有資料一律更新,新資料也會 insert

補充:Sqoop eval 操作 Oracle DB 遇到的小問題

在做 import 或 export 之前,個人習慣會先用 eval 檢查來源或目標 RDB 的 table。在一次對 Oracle DB 下 SELECT 的時候,報出「SQL command not properly ended」的錯誤

整個莫名其妙,那個 SELECT 就只有這樣:

SELECT COUNT(*)
FROM table_name;

查了半天,半信半疑的照著 Stack Overflow 上說的將結尾的分號去掉,竟然就成功了!?

這是一個比較奇怪的問題,有人說是在透過 JDBC/ODBC 對 Oracle 進行操作的時候不能加分號,不確定是為什麼,只能在遇到 Oracle DB 的時候記得去掉

--

--

Ticy Yang
Ticy Yang

Written by Ticy Yang

喜歡動手實作的 Data Engineer,期許自己在 Data 領域不斷精進 Do not go gentle into that good night. GitHub: https://github.com/TicyYang?tab=repositories

No responses yet