使用sqoop將mysql與Oracle中的數據按照日期與時間段分區存入hdfs中

今天遇到一個需求,這裏簡單介紹一下。原先把很多的信息都彙總到一個trace的表中,其中包括人臉識別後的對比數據、某學校卡口的進入車輛數據、訪客記錄、門禁刷卡記錄與一卡通消費記錄等,然後在HUE中新建一個WorkFlow,每天的凌晨進行增量導入與數據處理。後面甲方那邊感覺彙總的很好,結果要求按照小時更新。這個對於之前結構變化就有點大了,原先sqoop都是overwrite數據表,然後在hive裏面處理就好了。現在如果按照小時的話,就要增量導入到hive中,其中各個數據存儲也不能跟之前一樣直接導入到hdfs中,現在就需要根據日期與小時數分區存入數據到hdfs中。

後面我會講解一下解決的步驟。首先還是先寫好指令在shell裏面先自己測試一下,看看能不能通過sqoop按照日期和小時數分區導入數據到hdfs中。

一、設置兩個參數,獲取當天日期與上一小時數

這裏因爲這寫sqoop語句會寫在一個sh文件中,按照分區導入的日期和小時數會外部傳入參數進去,所以爲了模擬這個效果,我在測試時候現在shell中設置date_today與hour兩個參數:

> date_today=`date -d "today" +%Y-%m-%d`
> hour=`date -d "-1 hour" +"%H"`

二、按照日期與小時數分區從Mysql中導入數據

中間遇到一些小問題,這裏先直接貼成功的代碼。

sqoop import  --connect "jdbc:mysql://192.168.102.18:3306/school?useUnicode=true&characterEncoding=utf-8" --username root --password P@ssw0rd4321 --driver com.mysql.jdbc.Driver --query 'select * from snap_match where alarmTime>date_sub(date_format(now(), "%Y-%m-%d %H"), interval 1 hour) and alarmTime<date_format(now(), "%Y-%m-%d %H") and $CONDITIONS' --target-dir /user/activemq_topic/snap_match/$date_today/$hour --fields-terminated-by '\t' --lines-terminated-by '\n' --null-string '\\N' --null-non-string '\\N' --m 1;

錯誤a.首先看這個SQL語句:

select * from snap_match where alarmTime>date_sub(date_format(now(), "%Y-%m-%d %H"), interval 1 hour) and alarmTime<date_format(now(), "%Y-%m-%d %H")

之前這裏的雙引號我都是用的單引號,但是這樣會跟外部的單引號衝突,導致後面的sql語句解析不了。所以需要改成這的雙引號。

錯誤b.改成雙引號後執行又出了個錯:

可以很明顯的看到說缺少了$CONDITIONS,然後我去查了查,如果用了where的判斷的話,則一定要在後面加上 $CONDITIONS條件。

這裏邊幾點需要注意的坑:

1.“–connect “:CDH Sqoop1 使用 裏邊用一些 JDBC Connection Strings 的語法介紹和例子,但是 Oracle 的我試了不行,正確的寫法應該如:jdbc:oracle:thin:@<HOST>:<PORT>:<DATABASE_NAME>,區別在於 thin 後邊是需要又一個 冒號 的,很容易錯,還有 與 中間的連接也是冒號,因爲有的寫法是 “/“,但是這裏需要注意的是,這裏是 冒號。

 

2.“–query“:如果這裏SQL語句裏邊用過單引號了,那外邊必須要用雙引號;

  •     這裏的SQL假如直接使用 “FROM STORE“的話,是會報 table 找不見,或者不存在的,因爲使用“–query“的話沒有指定 Schema ,所以這裏必須使用 '.'的形式
  •     where 後邊必須有 $CONDITIONS 條件,sqoop 運行的時候,看日誌發現sqoop 會在這裏插入(1=0)或(1=1)來控制這條語句的執行。外邊使用雙引號的話,$CONDITIONS 前邊需要加反斜槓 即:\$CONDITIONS。 Free form query in Sqoop Import with WHERE clause

3.“–split-by” :需要指定一個 int 類型的列名,一般是主鍵。sqoop 會計算這個字段的 MIN 和 MAX ,然後結合 fetchSize 來確定 怎麼切分數據塊。這個字段必填。

4.“–direct“:沒加這個之前,導入特別慢,中間經常會出現 “Connect reset“,這個沒關係,一會兒它又回自動連接上。但是確實太慢了。使用這個字段後,導入速度又快又穩定,這個字段代表的意思應該是 使用的是關係數據庫自帶的導入導出工具。最好加上這個字段配置。

所以因爲我在sql中用了 where,所以需要添加這個條件 $CONDITIONS  。然後mysql導入數據執行成功。

三、按照日期與小時數分區從Oracle中導入數據

這裏從Oracle導入數據問題又跟MySQL中遇到的不一樣,就單獨出來彙總到這篇博客中:

https://blog.csdn.net/JJBOOM425/article/details/105574161

這裏也直接給測試成功的指令:

sqoop import --connect jdbc:oracle:thin:@192.168.99.19:1521:jcxydb --username sjbzk --password sjbzk --driver oracle.jdbc.driver.OracleDriver --query "SELECT * FROM GXTS_MJSKXX WHERE TO_DATE(SKSJ,'yyyy-mm-dd HH24:mi:ss')>TO_DATE(TO_DATE(sysdate-1/24,'yyyy-mm-dd HH24'),'yyyy-mm-dd HH24:mi:ss') AND TO_DATE(SKSJ,'yyyy-mm-dd HH24:mi:ss')<TO_DATE(TO_DATE(sysdate,'yyyy-mm-dd HH24'),'yyyy-mm-dd HH24:mi:ss') AND \$CONDITIONS" --target-dir /user/jcxydb/GXTS_MJSKXX/$date_today/$hour --fields-terminated-by '\t' --lines-terminated-by '\n' --null-string '\\N' --null-non-string '\\N' --m 1;

執行這兩條指令一定記得第一步的兩個參數,因爲這裏  --target-dir /user/jcxydb/GXTS_MJSKXX/$date_today/$hour  這個參數是hdfs的目的路徑,可以看到這裏有兩個外部傳入的參數作爲其中的路徑。所以要先給這兩個參數賦值,不然會有問題。

拓展與延伸:

這裏雖然成功了,但是後面繼續鼓搗的時候還遇到一個問題,還好大佬及時提出了。可以看  --fields-terminated-by '\t'  這個參數。它就是字段分割符,這裏要注意hive是有自己的默認字段分隔符的,不瞭解的童鞋可以百度看看。是 '\001' ,所以這裏我寫了 '\t' 那麼後面我hive在load的時候則要記得將字段分隔符改爲 '\t' ,不然兩邊不匹配則會失敗。不過爲了更方便一點,我後面也將這個參數就改爲  '\001'

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