原博客地址:http://blog.csdn.net/evankaka
摘要:本文主要講了筆者在使用sqoop過程中的一些實例
一、概述與基本原理
Apache Sqoop(SQL-to-Hadoop) 項目旨在協助 RDBMS 與 Hadoop 之間進行高效的大數據交流。用戶可以在 Sqoop 的幫助下,輕松地把關系型數據庫的數據導入到 Hadoop 與其相關的系統 (如Hbase和Hive)中;同時也可以把數據從 Hadoop 系統里抽取並導出到關系型數據庫里。因此,可以說Sqoop就是一個橋梁,連接了關系型數據庫與Hadoop。qoop中一大亮點就是可以通過hadoop的mapreduce把數據從關系型數據庫中導入數據到HDFS。Sqoop架構非常簡單,其整合了Hive、Hbase和Oozie,通過map-reduce任務來傳輸數據,從而提供並發特性和容錯。Sqoop的基本工作流程如下圖所示:


Sqoop在import時,需要制定split-by參數。Sqoop根據不同的split-by參數值來進行切分,然后將切分出來的區域分配到不同map中。每個map中再處理數據庫中獲取的一行一行的值,寫入到HDFS中(由此也可知,導入導出的事務是以Mapper任務為單位)。同時split-by根據不同的參數類型有不同的切分方法,如比較簡單的int型,Sqoop會取最大和最小split-by字段值,然后根據傳入的num-mappers來確定划分幾個區域。 比如select max(split_by),min(split-by) from得到的max(split-by)和min(split-by)分別為1000和1,而num-mappers為2的話,則會分成兩個區域(1,500)和(501-100),同時也會分成2個sql給2個map去進行導入操作,分別為select XXX from table where split-by>=1 and split-by<500和select XXX from table where split-by>=501 and split-by<=1000。最后每個map各自獲取各自SQL中的數據進行導入工作。
二、使用實例
接下來將以實例來說明如何使用
1、創建表
sqoop可以將MySQL表或其它關系型數據庫的表結構自動映射到Hive表。映射后的表結構為textfile格式。先來看一個腳本
#!/bin/sh . ~/.bashrc host='xx.xx.xx.xx' database='cescore' user='xxxx' password='xxxx' mysqlTable='yyyyyyy' hiveDB='ods_uba' hiveTable='yyyyyy' sqoop create-hive-table \ --connect jdbc:mysql://${host}:3306/${database} --username ${user} --password ${password} \ --table ${mysqlTable} \ --hive-table ${hiveDB}.${hiveTable} \ --hive-overwrite --hive-partition-key req_date \ rm *.java
--connect 指明連接的類型,基本所有的關系型數據庫都可以
--table 指明要源表的表名
--hive-table 指明要創建的Hive表名
--hive-overwrite 指明是否覆蓋插入(將原來的分區數據全刪除,再插入)
--hive-partition-key 指明分區的字段
我們可以到Hive去查看對應的表結構:

2、從mysql導數據到Hive
sqoop可以將數據從關系型數據庫導到Hive或Hive導到關系型數據庫,先來看一個從mydql導數據到Hive的實例,示例腳本如下
先來看一個腳本
#!/bin/sh . ~/.bashrc host='xx.xx.xx.xx' database='xxxcc' user='xxxx' password='xxxx' mysqlTable='sys_approve_reject_code' hiveDB='ods_uba' hiveTable='sys_approve_reject_code' tmpDir='/user/hive/warehouse/ods_uba.db/'${hiveTable} sqoop import --connect jdbc:mysql://${host}:3306/${database} --username ${user} --password ${password} \ --query "select * from "${database}"."${mysqlTable}" where 1 = 1 and \$CONDITIONS" \ --hive-import --hive-table ${hiveDB}.${hiveTable} --target-dir ${tmpDir} --delete-target-dir --split-by approve_reject_code \ --hive-overwrite \ --null-string '\\N' --null-non-string '\\N'
一般情況下,如果Hive里的表不存在,也可以不用執行第一步的創建表的步驟,因為一般導數時,它如果發現hive表不存在,會自己幫你創建表,Hive表的數據結構就和mysql的一樣。不過,這樣要注意一個點,如果Hive表是你自己通過Hive的交互命令行建立起來的,並且存儲格式設置為orc,那么使用sqoop導數據到這個表時是可以導入成功,但是會發現無法查詢出來,或者查詢亂碼。只能設置成textfile才可以。
上面的sql是將表全量導入到Hive中,不進行分區操作,每次導數都會將原來的數據刪除,因為這是一張字典表,所以需要這么做。來看看各字段的含義
--query 指明查詢的sql語句,注意主里加了一個 and \$conditions ,這是必需的,如果有帶where條件的話
--hive-table 指明目標表名
--target-dir 指明目標表的hdfs路徑
--delete-target-dir 刪除目標hfds路徑數據
--split-by 指明shuffle的字段,一般是取主鍵
--hive-overwrite 先刪除舊數據,再重新插入
--null-string --對null字符串和處理,映射成hive里的null
--null-non-string --對null非字符串和處理,映射成hive里的null
3、從phoenix導數據到Hive
下面再來看一個比較復雜的腳本,這里將從phoenix導數據,並將一天的數據分成24份
#!/bin/sh . ~/.bashrc #導數據,注意要傳入一個yyyy-mm-dd類型參數 synData(){ echo "您要統計數據的日期為:$statisDate" #生成每小時的查詢條件 for i in `seq 24` do num=$(echo $i) doSqoop $statisDate $num done } #sqoop導數據 doSqoop(){ echo "輸入日期:$statisDate,輸入序列號:$num" timeZone=$(printf "%02d\n" $(expr "$num" - "1")) partitionTime=$(echo "$statisDate-$timeZone") evtNOPre=$(echo $partitionTime | sed 's/\-//g') echo "分區字段:$partitionTime" where_qry=$(echo "evt_no like '$evtNOPre%'") echo $where_qry hiveDB='ods_uba' hiveTable='evt_log' tmpDir='/user/hive/warehouse/ods_uba.db/'${hiveTable} sqoop import -D mapreduce.map.memory.mb=3072 --driver org.apache.phoenix.jdbc.PhoenixDriver \ --connect jdbc:phoenix:xxxxxxxx \ --query "select * from uba.evt_log where $where_qry and \$CONDITIONS" \ --hive-import --hive-table ${hiveDB}.${hiveTable} --target-dir ${tmpDir} --delete-target-dir --split-by evt_no \ --hive-overwrite --hive-partition-key partition_time --hive-partition-value ${partitionTime} \ --null-string '\\N' --null-non-string '\\N' rm *.java } #統計日期默認取昨天 diffday=1 statisDate=`date +"%Y-%m-%d" -d "-"${diffday}"day"` #首先判斷是否有輸入日期,以及輸入日期是否合法,如果合法,取輸入的日期。不合法報錯,輸入日期為空,取昨天 if [ $# -eq 0 ]; then echo "您沒有輸入參數" synData $statisDate elif [ $# -eq 1 ]; then echo "您輸入參數為: $1 " statisDate=$1 if [ ${#statisDate} -eq 10 ];then synData $statisDate else echo "您輸入日期不合法,請輸入yyyy-mm-dd類型參數" fi else echo "您輸入參數多於一個,請不要輸入或只輸入一個yyyy-mm-dd類型參數" fi
-D mapreduce.map.memory.mb=3072,這是一個非常有用的參數,一般如果數據量非常大,在抽數據時有可能報內存不足,這時可以通過調高這個參數。
--driver 這里指明了使用的驅動類型,注意要將對應的驅動連接包放到sqoop對應的lib目錄下,要不會報錯
--hive-partition-key 指明分區字段
--hive-partition-value 指明分區值
這里因為是每天抽數,所以按天進行分區,因為還將每天分成了24個小時,理論上講設置成兩個分區字段會好點,但是sqoop只支持設置一個分區字段,所以這里的分區字段會被設計成yyyy-mm-dd-hh的類型
4、從mysql到hbse
sqoop import --connect jdbc:mysql://localhost/acmedb \ --table ORDERS --username test --password **** \ --hbase-create-table --hbase-table ORDERS --column-family mysql
--hbase-create-table: 指明使用sqoop創建hbse表
--hbase-table: hbase表
--column-family: --指明列族,將所有的mysql的列都放在這個列族下面