通過這麼幾天的折騰,發現 Sqoop1 真的比 Sqoop2 方便好用的多,Sqoop2 坑真是太多了,搞不定。Sqoop1 坑少也穩定,可是零基礎使用過程當中也是有幾點須要注意的。html
官方下載:Sqoop 官網
官方使用文檔
Sqoop-1.4.6安裝部署及詳細使用介紹
若是像我同樣直接用CDH裏邊自帶的話,方便的地方是環境變量什麼的不須要我再去配置了,很方便。
要檢查安裝成功沒,直接 sqoop version
;mysql
1 :
可能會出現警告:
accumulo does not exist! Accumulo imports will fail.
hcatalog does not exist! hcatalog imports will fail.
方法一:
CDH官方方法,以下:
Services that you want to use with Sqoop, such as HBase, Hive HCatalog, and Accumulo. When you run Sqoop, it checks to see if these services are installed and configured. It logs warnings for services it does not find. These warnings, shown below, are harmless. You can suppress these error messages by setting the variables $HBASE_HOME, $HCAT_HOME and $ACCUMULO_HOME to any existing directory.sql
即:只須要把 $HBASE_HOME, $HCAT_HOME and $ACCUMULO_HOME 設置爲任意一個存在的目錄便可。好比我:export ACCUMULO_HOME=/root
, 果真就不報警告了,很是簡單方便,強烈推薦。並且使用方法二的話直接修改了配置文件頗有可能會出問題,不安全數據庫
方法二:
若是不須要,能夠屏蔽它;
到 「SQOOP_HOME/bin」 下編輯 configure-sqoop,註釋掉裏邊與Accumulo 和 hcatalog 有關的代碼塊,不是太難,本身打開看看這個文件就知道了。apache
2:要注意 「–target-dir」 須要指定一個空的不存在的文件夾,不能指定已經存在的文件夾,它會本身建立的安全
3:一個 從 Oracle 到 HDFS 的 import 語句:oracle
sqoop import --connect jdbc:oracle:thin:@<HOST>:1521:app --username user --P --query "select * from HD.STORE where \$CONDITIONS and RCVTIME < TO_TIMESTAMP('2017-05-30 00:00:00','yyyy-mm-dd hh24:mi:ss.ff')" --split-by id --direct --target-dir /user/root/store --m 1
這裏邊幾點須要注意的坑:app
「–connect 「:CDH Sqoop1 使用 裏邊用一些 JDBC Connection Strings 的語法介紹和例子,可是 Oracle 的我試了不行,正確的寫法應該如:jdbc:oracle:thin:@<HOST>:<PORT>:<DATABASE_NAME>
,區別在於 thin 後邊是須要又一個 冒號 的,很容易錯,還有 與 中間的鏈接也是冒號,由於有的寫法是 「/「,可是這裏須要注意的是,這裏是 冒號。less
「–query「:ide
這裏的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
「–split-by」 :須要指定一個 int 類型的列名,通常是主鍵。sqoop 會計算這個字段的 MIN 和 MAX ,而後結合 fetchSize 來肯定 怎麼切分數據塊。這個字段必填。
爲了方便複用,咱們能夠把一串命令和參數寫入txt文件中,使用 –options-file 來調用。詳細使用方法,官方文檔的 6.4 Using Options Files to Pass Arguments 裏寫的特別清楚了。由於是英文的,我這裏簡單給英文很差的同窗說一下要點和更命令行方式對比須要注意的:
先上一個等同上面命令行例子的例子。
store_import.txt
# # import options file of STORE table # # # oracle table STORE to hive table * # import --connect jdbc:oracle:thin:@<HOST>:1521:app --username user --password 123456 --query select * from HD.STORE where $CONDITIONS and \ RCVTIME < TO_TIMESTAMP('2017-05-30 00:00:00','yyyy-mm-dd hh24:mi:ss.ff') --split-by FLOWNO --direct --target-dir /user/root/store --m 1
用時,
$ sqoop --options-file /users/home/store_import.txt
--password
直接寫入密碼,方便自動執行;命令行裏咱們用的是-P
,用-P
爲了安全,在命令行執行時須要手動輸入密碼,並且不會明文顯示變化較大的是 --query
參數後邊的SQL語句,須要注意:
$CONDITIONS
前邊再也不須要反斜槓來轉換$
符號了上面的例子都是從 oracle 導入 hdfs 的,如今咱們用 sqoop 來直接導入 Hive。
官方文檔 7.2.12. Importing Data Into Hive
而後再上個人例子,
import --hive-import --hive-table dw_hd.ods_store --connect jdbc:oracle:thin:@<HOST>:1521:app --username user --password 123456 --query select * from HD.STORE where $CONDITIONS and \ RCVTIME < TO_TIMESTAMP('2017-05-30 00:00:00','yyyy-mm-dd hh24:mi:ss.ff') --split-by FLOWNO --direct --target-dir /user/root/store --null-string '\\N' --null-non-string '\\N' --m 2
sqoop 導入 Hive 分三步:
1. 先導入--target-dir
指定的 HDFS 的目錄中
2. 在 Hive 中建表
3. 調用 Hive 的 LOAD DATA INPATH
把 --target-dir
中的數據移動到 Hive 中
觀察上邊例子與前邊的作對比,有如下幾點不一樣:
--hive-import
:指定是導入 Hive--hive-table
:導入 Hive 中的數據庫名和表名--null-string
和 --null-non-string
:分別表明了 sqoop 對 字符串類型 null 值 和 非字符串類型 null 值 的處理。若是不指定的話,默認導入 Hive 後 字符串類型的 null 值是 ‘null’,非字符串類型 null 值是 ‘NULL’,這裏用把這兩種狀況統一成了 ‘NULL’,sqoop 中用 ‘\N’,若是想要小寫的 ‘null’ 的話,使用 ‘\N’。問題1:導入後從Hive中查到的數據條數比實際從關係數據庫中查到的條數多?
解決:緣由是使用--hive-import
會使用默認的 Hive 的分隔符,值分隔符^A
和行分隔符\n
。官方文檔 7.2.12. Importing Data Into Hive 裏原文以下:
Hive will have problems using Sqoop-imported data if your database’s rows contain string fields that have Hive’s default row delimiters (\n
and \r
characters) or column delimiters (\01
characters) present in them. You can use the --hive-drop-import-delims
option to drop those characters on import to give Hive-compatible text data. Alternatively, you can use the --hive-delims-replacement
option to replace those characters with a user-defined string on import to give Hive-compatible text data. These options should only be used if you use Hive’s default delimiters and should not be used if different delimiters are specified.
Sqoop will pass the field and record delimiters through to Hive. If you do not set any delimiters and do use --hive-import
, the field delimiter will be set to ^A
and the record delimiter will be set to \n
to be consistent with Hive’s defaults.
這樣問題就來了,若是導入的數據中有’\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
做爲行分隔符。
ORACLE中查詢某個字段包含 回車 換行 符,
||
不是或,是 oracle 中的字符串鏈接符。%
是通配符,表明任意字符串。
查看是否包含 回車換行 符,即:\r\n
select * from system.test_tab1 where name like '%'||chr(13)||chr(10)||'%'
單獨查看是否包含 回車換行 符,即:\r
select * from system.test_tab1 where name like '%'||chr(13)||'%'
單獨查看是否包含 換行 符,即:\n
select * from system.test_tab1 where name like '%'||chr(10)||'%'
解決方法:簡單的解決辦法就是加上參數--hive-drop-import-delims
來把導入數據中包含的hive默認的分隔符去掉。這個最簡單,若是肯定數據中不應含有這些字符的話,或者肯定去掉沒影響的話,能夠用這個。另外,使用這個就無法使用 --direct
選項了。
7.2.9. Incremental Imports
問題:–incremental lastmodified 模式 不支持 導入Hive
--incremental lastmodified option for hive imports is not supported. Please remove the parameter --incremental lastmodified.
解決辦法:使用導入HDFS 的方法,只不過 --target-dir
設置成 Hive table 在 HDFS 中的位置,相似於/user/hive/warehouse/store
,前提 Hive 中已經存在這個表了,不存在的話先CREATE。
sqoop incremental import to hive table
問題1:導入後每一行全部數據都在第一個字段裏?
緣由和解決:由於直接導入 HDFS 中 HIve 裏的文件夾下的話,sqoop 默認給的 值分隔符 是逗號 ,
,而 Hive 默認值分割符是\001
,即:^A
,因此 Hive 是不認的,因此 須要 把值分隔符改爲 ^A
,即加上下邊的配置:
--fields-terminated-by \001
問題2:仍是上邊那個問題,導入後從Hive中查到的數據條數比實際從關係數據庫中查到的條數多?
緣由和解決:這樣子增量導入時,由於直接是導入 hdfs 的,不是 --hive-import
,因此就無法 用 --hive-drop-import-delims
去掉衝突的分隔符了。因此就又會出現上邊那個問題。解決辦法是:在 --query
後的SQL語句裏作 replace 方法嵌套作替換,把\r
和\n
分別替換爲空字符串, REPLACE(REPLACE(name,CHR(13),''),CHR(10),'')
,以下:
--query select REPLACE(REPLACE(name,CHR(13),''),CHR(10),'') name,code from test
文檔 12. Saved Jobs
用 sqoop job 作增量更新,它會在它的 metastore 中管理 --last-value
,很方便。
sqoop job --create test_import_store -- --options-file /root/sqoop_option_files/store_import.txt
這裏有一個很弱智的坑,很容易栽進來,困了我快一天。
通常網上定義job的例子以下:
sqoop job --create user_info -- import --connect jdbc:mysql://mysql-server-ip:3306/sqoop --username root --password root --table user_info -m 1
看這裏,sqoop job --create user_info -- import
,看到了嗎,’–’ 和 ‘import’ 之間有一個空格,很容易忽視的一點。這裏用 ‘–’ 來指示 job 的內容,第一次見,很容易把 –import 當成一個總體。不注意這個,就會一直報 不能識別的參數
ERROR tool.BaseSqoopTool: Unrecognized argument
這裏我以爲,sqoop job 和 –options-file 一塊用才更配,很方便去編輯 job,以下同樣的模版,很容易避開上邊那個坑。
sqoop job --create <job_name> -- --options-file <options-file-txt-path>
默認每次執行 job 時都須要手動輸入密碼。這樣很不利於自動化任務和 Oozie 調度,因此須要設置在 sqoop metastore 中保存密碼。
You can enable passwords in the metastore by setting sqoop.metastore.client.record.password to true in the configuration.
解決方式有兩種:
第一種方式,使用password-file;
第二種方式,在sqoop-site.xml中添加以下屬性便可(添加後第一次仍然須要輸入密碼 )。
<property> <name>sqoop.metastore.client.record.password</name> <value>true</value> </property>
Sqoop詳細介紹包括:sqoop命令,原理,流程
Sqoop使用手冊