1. 程式人生 > >sqoop 特殊字元匯入問題

sqoop 特殊字元匯入問題

Sqoop從MySQL匯入資料到hive,示例:
sqoop import –connect jdbc:mysql://10.255.2.89:3306/test?charset=utf-8 – username selectuser –password select##select## –table test_sqoop_import \
–columns ‘id,content,updateTime’ \
–split-by id \
–hive-import –hive-table basic.test2;

如果不加其他引數,匯入的資料預設的列分隔符是’\001’,預設的行分隔符是’\n’。
這樣問題就來了,如果匯入的資料中有’\n’,hive會認為一行已經結束,後面的資料被分割成下一行。這種情況下,匯入之後hive中資料的行數就比原先資料庫中的多,而且會出現資料不一致的情況。
Sqoop也指定了引數 –fields-terminated-by和 –lines-terminated-by來自定義行分隔符和列分隔符。
可是當你真的這麼做時 坑爹呀
INFO hive.HiveImport: FAILED: SemanticException 1:381 LINES TERMINATED BY only supports newline ’\n’ right now.    也就是說雖然你通過–lines-terminated-by指定了其他的字元作為行分隔符,但是hive只支援’\n’作為行分隔符。
簡單的解決辦法就是加上引數–hive-drop-import-delims來把匯入資料中包含的hive預設的分隔符去掉。

附 sqoop 命令參考

匯入資料到 hdfs
使用 sqoop-import 命令可以從關係資料庫匯入資料到 hdfs。
$ sqoop import –connect jdbc:mysql://192.168.56.121:3306/metastore –username hiveuser –password redhat –table TBLS –target-dir /user/hive/result 注意:
mysql jdbc url 請使用 ip 地址
如果重複執行,會提示目錄已經存在,可以手動刪除
如果不指定 –target-dir,匯入到使用者家目錄下的 TBLS 目錄
你還可以指定其他的引數:

--append	將資料追加到hdfs中已經存在的dataset中。使用該引數,sqoop將把資料先匯入到一個臨時目錄中,然後重新給檔案命名到一個正式的目錄中,以避免和該目錄中已存在的檔案重名。  
--as-avrodatafile	將資料匯入到一個Avro資料檔案中  
--as-sequencefile	將資料匯入到一個sequence檔案中  
--as-textfile	將資料匯入到一個普通文字檔案中,生成該文字檔案後,可以在hive中通過sql語句查詢出結果。  
--boundary-query <statement>	邊界查詢,也就是在匯入前先通過SQL查詢得到一個結果集,然後匯入的資料就是該結果集內的資料,格式如:--boundary-query 'select id,no from t where id = 3',表示匯入的資料為id=3的記錄,或者 select min(<split-by>), max(<split-by>) from <table name>,注意查詢的欄位中不能有資料型別為字串的欄位,否則會報錯
--columns<col,col>	指定要匯入的欄位值,格式如:--columns id,username
--direct	直接匯入模式,使用的是關係資料庫自帶的匯入匯出工具。官網上是說這樣匯入會更快
--direct-split-size	在使用上面direct直接匯入的基礎上,對匯入的流按位元組數分塊,特別是使用直連模式從PostgreSQL匯入資料的時候,可以將一個到達設定大小的檔案分為幾個獨立的檔案。
--inline-lob-limit	設定大物件資料型別的最大值
-m,--num-mappers	啟動N個map來並行匯入資料,預設是4個,最好不要將數字設定為高於叢集的節點數
--query,-e <sql>	從查詢結果中匯入資料,該引數使用時必須指定–target-dir、–hive-table,在查詢語句中一定要有where條件且在where條件中需要包含 \$CONDITIONS,示例:--query 'select * from t where \$CONDITIONS ' --target-dir /tmp/t –hive-table t
--split-by <column>	表的列名,用來切分工作單元,一般後面跟主鍵ID
--table <table-name>	關係資料庫表名,資料從該表中獲取
--delete-target-dir	刪除目標目錄
--target-dir <dir>	指定hdfs路徑
--warehouse-dir <dir>	與 --target-dir 不能同時使用,指定資料匯入的存放目錄,適用於hdfs匯入,不適合匯入hive目錄
--where	從關係資料庫匯入資料時的查詢條件,示例:--where "id = 2"
-z,--compress	壓縮引數,預設情況下資料是沒被壓縮的,通過該引數可以使用gzip壓縮演算法對資料進行壓縮,適用於SequenceFile, text文字檔案, 和Avro檔案
--compression-codec	Hadoop壓縮編碼,預設是gzip
--null-string <null-string>	可選引數,如果沒有指定,則字串null將被使用
--null-non-string <null-string>	可選引數,如果沒有指定,則字串null將被使用

使用 sql 語句
參照上表,使用 sql 語句查詢時,需要指定 $CONDITIONS

$ sqoop import –connect jdbc:mysql://192.168.56.121:3306/metastore –username hiveuser –password redhat –query ‘SELECT * from TBLS where $CONDITIONS ‘ –split-by tbl_id -m 4 –target-dir /user/hive/result
上面命令通過 -m 1 控制併發的 map 數。

使用 direct 模式:
$ sqoop import –connect jdbc:mysql://192.168.56.121:3306/metastore –username hiveuser –password redhat –table TBLS –delete-target-dir –direct –default-character-set UTF-8 –target-dir /user/hive/result

指定檔案輸出格式:
$ sqoop import –connect jdbc:mysql://192.168.56.121:3306/metastore –username hiveuser –password redhat –table TBLS –fields-terminated-by “\t” –lines-terminated-by “\n” –delete-target-dir –target-dir /user/hive/result

指定空字串:
$ sqoop import –connect jdbc:mysql://192.168.56.121:3306/metastore –username hiveuser –password redhat –table TBLS –fields-terminated-by “\t” –lines-terminated-by “\n” –delete-target-dir –null-string ‘\N’ –null-non-string ‘\N’ –target-dir /user/hive/result

如果需要指定壓縮: 
$ sqoop import –connect jdbc:mysql://192.168.56.121:3306/metastore –username hiveuser –password redhat –table TBLS –fields-terminated-by “\t” –lines-terminated-by “\n” –delete-target-dir –null-string ‘\N’ –null-non-string ‘\N’ –compression-codec “com.hadoop.compression.lzo.LzopCodec” –target-dir /user/hive/result

附:可選的檔案引數如下表。

--enclosed-by <char>	給欄位值前後加上指定的字元,比如雙引號,示例:--enclosed-by '\"',顯示例子:"3","jimsss","[email protected]"
--escaped-by <char>	給雙引號作轉義處理,如欄位值為"測試",經過 --escaped-by "\\" 處理後,在hdfs中的顯示值為:\"測試\",對單引號無效
--fields-terminated-by <char>	設定每個欄位是以什麼符號作為結束的,預設是逗號,也可以改為其它符號,如句號.,示例如:--fields-terminated-by
--lines-terminated-by <char>	設定每條記錄行之間的分隔符,預設是換行串,但也可以設定自己所需要的字串,示例如:--lines-terminated-by "#" 以#號分隔
--mysql-delimiters	Mysql預設的分隔符設定,欄位之間以,隔開,行之間以換行\n隔開,預設轉義符號是\,欄位值以單引號'包含起來。
--optionally-enclosed-by <char>	enclosed-by是強制給每個欄位值前後都加上指定的符號,而--optionally-enclosed-by只是給帶有雙引號或單引號的欄位值加上指定的符號,故叫可選的

建立 hive 表
生成與關係資料庫表的表結構對應的HIVE表:

$ sqoop create-hive-table --connect jdbc:mysql://192.168.56.121:3306/metastore --username hiveuser --password redhat --table TBLS 
--hive-home <dir>	Hive的安裝目錄,可以通過該引數覆蓋掉預設的hive目錄
--hive-overwrite	覆蓋掉在hive表中已經存在的資料
--create-hive-table	預設是false,如果目標表已經存在了,那麼建立任務會失敗
--hive-table	後面接要建立的hive表
--table	指定關係資料庫表名  匯入資料到 hive   執行下面的命令會將 mysql 中的資料匯入到 hdfs 中,然後建立一個hive 表,最後再將 hdfs 上的檔案移動到 hive 表的目錄下面。   $ sqoop import --connect jdbc:mysql://192.168.56.121:3306/metastore --username hiveuser --password redhat --table TBLS --fields-terminated-by "\t" --lines-terminated-by "\n" --hive-import --hive-overwrite --create-hive-table --hive-table dw_srclog.TBLS --delete-target-dir   說明:   可以在 hive 的表名前面指定資料庫名稱   可以通過 --create-hive-table 建立表,如果表已經存在則會執行失敗   從上面可見,資料匯入到 hive 中之後分隔符為預設分隔符,參考上文你可以通過設定引數指定其他的分隔符。   另外,Sqoop 預設地匯入空值(NULL)為 null 字串,而 hive 使用 \N 去標識空值(NULL),故你在 import 或者 export 時候,需要做相應的處理。在 import 時,使用如下命令:   $ sqoop import  ... --null-string '\\N' --null-non-string '\\N'   在匯出時,使用下面命令:   $ sqoop import  ... --input-null-string '' --input-null-non-string ''

增量匯入
–check-column (col) 用來作為判斷的列名,如id
–incremental (mode) append:追加,比如對大於last-value指定的值之後的記錄進行追加匯入。lastmodified:最後的修改時間,追加last-value指定的日期之後的記錄
–last-value (value) 指定自從上次匯入後列的最大值(大於該指定的值),也可以自己設定某一值

合併 hdfs 檔案
將HDFS中不同目錄下面的資料合在一起,並存放在指定的目錄中,示例如:
sqoop merge –new-data /test/p1/person –onto /test/p2/person –target-dir /test/merged –jar-file /opt/data/sqoop/person/Person.jar –class-name Person –merge-key id
其中,–class-name 所指定的 class 名是對應於 Person.jar 中的 Person 類,而 Person.jar 是通過 Codegen 生成的
–new-data Hdfs中存放資料的一個目錄,該目錄中的資料是希望在合併後能優先保留的,原則上一般是存放越新資料的目錄就對應這個引數。 --onto Hdfs中存放資料的一個目錄,該目錄中的資料是希望在合併後能被更新資料替換掉的,原則上一般是存放越舊資料的目錄就對應這個引數。 --merge-key <col> 合併鍵,一般是主鍵ID --jar-file 合併時引入的jar包,該jar包是通過Codegen工具生成的jar包 --class-name 對應的表名或物件名,該class類是包含在jar包中的。 --target-dir 合併後的資料在HDFS裡的存放目錄