上節(jié)課學(xué)習(xí)了Hadoop集群測(cè)試,這節(jié)課我們一起學(xué)習(xí)一下Sqoop府框,Sqoop是專(zhuān)門(mén)用來(lái)遷移數(shù)據(jù)的吱窝,它可以把數(shù)據(jù)庫(kù)中的數(shù)據(jù)遷移到HDFS文件系統(tǒng),當(dāng)然也可以從HDFS文件系統(tǒng)導(dǎo)回到數(shù)據(jù)庫(kù)。
我來(lái)說(shuō)一下Sqoop的使用場(chǎng)景院峡,假如你們公司有個(gè)項(xiàng)目運(yùn)行好長(zhǎng)時(shí)間了兴使,積累了大量的數(shù)據(jù),現(xiàn)在想升級(jí)項(xiàng)目并換種數(shù)據(jù)庫(kù)進(jìn)行存儲(chǔ)原來(lái)的數(shù)據(jù)撕予,那么我們就需要先把數(shù)據(jù)都存放到另一個(gè)地方鲫惶,然后再用新數(shù)據(jù)庫(kù)的語(yǔ)句把這些數(shù)據(jù)插入到新的數(shù)據(jù)庫(kù)。在沒(méi)有Sqoop之前实抡,我們要做到這一點(diǎn)是很困難的欠母,但是現(xiàn)在有了Sqoop,事情就變的簡(jiǎn)單多了吆寨,Sqoop是運(yùn)行在Hadoop之上的一個(gè)工具赏淌,底層運(yùn)用了MapReduce的技術(shù),多臺(tái)設(shè)備并行執(zhí)行任務(wù)啄清,速度當(dāng)然大大提高六水,而且不用我們寫(xiě)這方面的代碼,它提供了非常強(qiáng)大的命令辣卒,我們只需要知道怎樣使用這些命令掷贾,再加上一些SQL語(yǔ)句就可以輕輕松松實(shí)現(xiàn)數(shù)據(jù)的遷移工作。
接下來(lái)我們便正式開(kāi)始學(xué)習(xí)怎樣使用Sqoop荣茫。
第一步:環(huán)境準(zhǔn)備
1.1 從Sqoop官網(wǎng)下載安裝包并解壓到/itcast目錄
大家可以參考:http://blog.csdn.net/u012453843/article/details/52951277這篇博客下載**sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz**
Sqoop的運(yùn)行需要Yarn和HDFS想帅,它只需要知道Yarn的管理者角色ResourceManager和HDFS的管理者角色NameNode在哪臺(tái)設(shè)備上就可以,我們?cè)诖罱旱臅r(shí)候每臺(tái)設(shè)備上都有相同的6個(gè)配置文件啡莉,因此我們把Sqoop放到任何一臺(tái)設(shè)備上都可以「圩迹現(xiàn)在itcast03上的進(jìn)程是最少的,我們便把Sqoop放到itcast03上吧咧欣。
我們使用工具把sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz上傳到Itcast03的root根目錄下浅缸,如下圖所示。
接著我們把sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz解壓到/itcast目錄下魄咕,執(zhí)行的命令如下衩椒。
[root@itcast03 ~]#tar -zxvf sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz -C /itcast/
解壓完之后我們到/itcast目錄下查看一下,發(fā)現(xiàn)已經(jīng)有sqoop的包了哮兰,如下所示烟具。
[root@itcast03 ~]# cd /itcast/
[root@itcast03 itcast]# ls **hadoop-2.2.0****sqoop-1.4.6.bin__hadoop-2.0.4-alpha**
[root@itcast03 itcast]#
sqoop-1.4.6.bin__hadoop-2.0.4-alpha這么長(zhǎng)的名字我們操作起來(lái)不方便,給它起個(gè)簡(jiǎn)單的名字sqoop-1.4.6奠蹬,如下所示朝聋。
[root@itcast03 itcast]#**mv sqoop-1.4.6.bin__hadoop-2.0.4-alpha/ sqoop-1.4.6**
[root@itcast03 itcast]# ls
hadoop-2.2.0 **sqoop-1.4.6**
[root@itcast03 itcast]#
那么,我們用不用配置Sqoop呢囤躁,如果你的環(huán)境已經(jīng)配置了NameNode和ResourceManager在哪臺(tái)設(shè)備上冀痕,那么我們不用配置任何內(nèi)容便可以使用Sqoop荔睹,現(xiàn)在我們的集群環(huán)境中core-site.xml和hdfs-site.xml兩個(gè)文件指定了NameNode在哪兩臺(tái)設(shè)備上,yarn-site.xml指定了ResourceManager在哪臺(tái)設(shè)備上言蛇,因此我們不用作任何配置了僻他。
那么問(wèn)題又來(lái)了,Sqoop是怎么知道我們集群的配置呢腊尚,其實(shí)Sqoop會(huì)自動(dòng)去查找這臺(tái)設(shè)備上HADOOP_HOME的位置吨拗,找到之后它會(huì)自動(dòng)讀取hadoop下面的配置文件,從而它也就知道了NameNode和ResourceManager的位置婿斥。
[root@itcast03 itcast]#**echo $HADOOP_HOME **
**/itcast/hadoop-2.2.0**
[root@itcast03 itcast]#
1.2 安裝MySQL數(shù)據(jù)庫(kù)
大家可以參考:http://blog.csdn.net/u012453843/article/details/52951422這篇博客來(lái)下載并配置使用Mysql
1.3 Hadoop集群
大家可以參考:http://blog.csdn.net/u012453843/article/details/52829830這篇博客來(lái)搭建集群劝篷。
第二步:?jiǎn)?dòng)Sqoop
2.1 經(jīng)過(guò)了第一步的準(zhǔn)備工作后,我們終于可以來(lái)啟動(dòng)Sqoop了民宿,啟動(dòng)之前我們先看看Sqooop的目錄娇妓,如下所示』钣ィ可以看到哈恰,在sqoop-1.4.6的bin目錄下有很多命令,我們最最常用的便是sqoop了志群,它基本上能滿(mǎn)足我們的所有要求了着绷。因?yàn)樗竺婵梢越雍芏鄥?shù),這些參數(shù)的功能非常強(qiáng)大锌云。
[root@itcast03 itcast]# ls
hadoop-2.2.0 sqoop-1.4.6
[root@itcast03 itcast]# cd sqoop-1.4.6/
[root@itcast03 sqoop-1.4.6]# ls
bin conf lib README.txt src
build.xml docs LICENSE.txt sqoop-1.4.6.jar testdata
CHANGELOG.txt ivy NOTICE.txt sqoop-patch-review.py
COMPILING.txt ivy.xml pom-old.xml sqoop-test-1.4.6.jar
[root@itcast03 sqoop-1.4.6]# cd bin
[root@itcast03 bin]# ls
configure-sqoop sqoop-export sqoop-list-tables
configure-sqoop.cmd sqoop-help sqoop-merge
sqoop sqoop-import sqoop-metastore
sqoop.cmd sqoop-import-all-tables sqoop-version
sqoop-codegen sqoop-import-mainframe start-metastore.sh
sqoop-create-hive-table sqoop-job stop-metastore.sh
sqoop-eval sqoop-list-databases
[root@itcast03 bin]#
我們?cè)賮?lái)看看sqoop-1.4.6的conf目錄荠医,conf目錄下有個(gè)sqoop-site.xml文件,在這里面我們可以配置一些個(gè)性化的內(nèi)容宾抓,這里我們可以不做任何處理。
[root@itcast03 sqoop-1.4.6]# cd conf/
[root@itcast03 conf]# ls
oraoop-site-template.xml sqoop-env-template.cmd sqoop-env-template.sh sqoop-site-template.xml sqoop-site.xml
[root@itcast03 conf]#
接下來(lái)我們便啟動(dòng)sqoop豫喧,我們還是先回到sqoop的bin目錄下石洗,然后使用命令**./sqooop**來(lái)啟動(dòng),啟動(dòng)的過(guò)程有很多警告紧显,這是因?yàn)槲覀冞€沒(méi)有安裝相關(guān)工具讲衫。我們不管它。
[root@itcast03 bin]# ./sqoop
Warning: /itcast/sqoop-1.4.6/bin/../../hbase does not exist! HBase imports will fail.
Please set $HBASE_HOME to the root of your HBase installation.
Warning: /itcast/sqoop-1.4.6/bin/../../hcatalog does not exist! HCatalog jobs will fail.
Please set $HCAT_HOME to the root of your HCatalog installation.
Warning: /itcast/sqoop-1.4.6/bin/../../accumulo does not exist! Accumulo imports will fail.
Please set $ACCUMULO_HOME to the root of your Accumulo installation.
Warning: /itcast/sqoop-1.4.6/bin/../../zookeeper does not exist! Accumulo imports will fail.
Please set $ZOOKEEPER_HOME to the root of your Zookeeper installation.
Try 'sqoop help' for usage.
[root@itcast03 bin]#
第三步:把Sqoop目錄配置到環(huán)境變量(這步可以不配置孵班,只是所有命令需要到sqoop的bin目錄下去操作涉兽,比較麻煩)
由于我們是在itcast03上操作sqoop的,因此我們便在itcast03上配置它的環(huán)境變量篙程,使用的命令是vim /etc/profile枷畏,在最下方添加我們的SQOOP_HOME,如下紅色字體的內(nèi)容就是我們要添加的內(nèi)容虱饿。
export JAVA_HOME=/usr/java/jdk1.7.0_80
export HADOOP_HOME=/itcast/hadoop-2.2.0
export SQOOP_HOME=/itcast/sqoop-1.4.6
export PATH=$JAVA_HOME/bin:$HADOOP_HOME/bin:$SQOOP_HOME/bin:$PATH
配置完環(huán)境變量之后別忘了使我們的環(huán)境變量生效拥诡,我們使用的命令是:source /etc/profile
第四步:導(dǎo)入
4**.1 我們現(xiàn)在想把數(shù)據(jù)庫(kù)sqoop下的Student表中的數(shù)據(jù)遷移到HDFS触趴,我們先看看Student表中都有哪些數(shù)據(jù),可以看到有10條數(shù)據(jù)渴肉,我們就要把這10條數(shù)據(jù)上傳到HDFS冗懦。(****需要注意的是:Student表一定要有主鍵,否則會(huì)有問(wèn)題**)
4.1.1 在開(kāi)始導(dǎo)入之前仇祭,我們需要先把jdbc的驅(qū)動(dòng)放到**/itcast/sqoop-1.4.6/lib**目錄下披蕉,驅(qū)動(dòng)包大家可以到官網(wǎng)下載也可以直接到:http://download.csdn.net/detail/u012453843/9667329這個(gè)網(wǎng)址下載**。**
[root@itcast03 ~]# ls
anaconda-ks.cfg Music
Desktop mysql-connector-java-5.1.40-bin.jar
Documents Pictures
Downloads Public
install.log sqoop-1.4.6.bin__hadoop-2.0.4-alpha.tar.gz
install.log.syslog Templates
jdk-7u80-linux-x64.gz Videos
[root@itcast03 ~]# cp mysql-connector-java-5.1.40-bin.jar /itcast/sqoop-1.4.6/lib
[root@itcast03 ~]#
4.1.2 設(shè)置你的itcast03設(shè)備可以遠(yuǎn)程登錄到數(shù)據(jù)庫(kù)乌奇。
默認(rèn)情況下我們的itcast03是無(wú)法遠(yuǎn)程登錄到數(shù)據(jù)庫(kù)的没讲,直接進(jìn)行導(dǎo)入操作的話(huà)會(huì)報(bào)如下錯(cuò)誤:
manager.SqlManager: **Error executing statement: java.sql.SQLException: null, message from server: "Host 'itcast03' is not allowed to connect to this MySQL server"**
java.sql.SQLException: null, message from server: "Host 'itcast03' is not allowed to connect to this MySQL server"
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1040)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2253)
at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2284)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2083)
at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:806)
at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:410)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:328)
at java.sql.DriverManager.getConnection(DriverManager.java:571)
at java.sql.DriverManager.getConnection(DriverManager.java:215)
at org.apache.sqoop.manager.SqlManager.makeConnection(SqlManager.java:885)
at org.apache.sqoop.manager.GenericJdbcManager.getConnection(GenericJdbcManager.java:52)
at org.apache.sqoop.manager.SqlManager.execute(SqlManager.java:744)
at org.apache.sqoop.manager.SqlManager.execute(SqlManager.java:767)
at org.apache.sqoop.manager.SqlManager.getColumnInfoForRawQuery(SqlManager.java:270)
at org.apache.sqoop.manager.SqlManager.getColumnTypesForRawQuery(SqlManager.java:241)
at org.apache.sqoop.manager.SqlManager.getColumnTypes(SqlManager.java:227)
at org.apache.sqoop.manager.ConnManager.getColumnTypes(ConnManager.java:295)
at org.apache.sqoop.orm.ClassWriter.getColumnTypes(ClassWriter.java:1833)
at org.apache.sqoop.orm.ClassWriter.generate(ClassWriter.java:1645)
at org.apache.sqoop.tool.CodeGenTool.generateORM(CodeGenTool.java:107)
at org.apache.sqoop.tool.ImportTool.importTable(ImportTool.java:478)
at org.apache.sqoop.tool.ImportTool.run(ImportTool.java:605)
at org.apache.sqoop.Sqoop.run(Sqoop.java:143)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:179)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:218)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:227)
at org.apache.sqoop.Sqoop.main(Sqoop.java:236)
16/10/29 02:21:06 ERROR tool.ImportTool: Encountered IOException running import job: java.io.IOException: No columns to generate for ClassWriter
at org.apache.sqoop.orm.ClassWriter.generate(ClassWriter.java:1651)
at org.apache.sqoop.tool.CodeGenTool.generateORM(CodeGenTool.java:107)
at org.apache.sqoop.tool.ImportTool.importTable(ImportTool.java:478)
at org.apache.sqoop.tool.ImportTool.run(ImportTool.java:605)
at org.apache.sqoop.Sqoop.run(Sqoop.java:143)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:179)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:218)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:227)
at org.apache.sqoop.Sqoop.main(Sqoop.java:236)
解決方法如下:
mysql -u root -p
mysql>use mysql;
mysql>select host from user where user='root';
mysql>update user set host = '%' where user ='root';
mysql>flush privileges;
mysql>select host from user where user='root';
第一句是以權(quán)限用戶(hù)root登錄
第二句:選擇mysql庫(kù)
第三句:查看mysql庫(kù)中的user表的host值(即可進(jìn)行連接訪問(wèn)的主機(jī)/IP名稱(chēng))
第四句:修改host值(以通配符%的內(nèi)容增加主機(jī)/IP地址),當(dāng)然也可以直接增加IP地址
第五句:刷新MySQL的系統(tǒng)權(quán)限相關(guān)表
第六句:再重新查看user表時(shí)华弓,有修改食零。。
重起mysql服務(wù)即可完成寂屏。
4.1.3 設(shè)置NameNode和DataNode時(shí)間同步贰谣,有可能NameNode和DataNode的時(shí)間是不同步的,這樣的話(huà)迁霎,在執(zhí)行導(dǎo)入操作的時(shí)候會(huì)報(bào)如下的錯(cuò)誤吱抚。
16/10/29 03:01:50 INFO mapreduce.Job: Job job_1477729967303_0001 failed with state FAILED due to: Application application_1477729967303_0001 failed 2 times due to Error launching appattempt_1477729967303_0001_000002. Got exception: org.apache.hadoop.yarn.exceptions.YarnException: Unauthorized request to start container.
This token is expired. current time is 1477736540684 found 1477735910751
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.apache.hadoop.yarn.api.records.impl.pb.SerializedExceptionPBImpl.instantiateException(SerializedExceptionPBImpl.java:152)
at org.apache.hadoop.yarn.api.records.impl.pb.SerializedExceptionPBImpl.deSerialize(SerializedExceptionPBImpl.java:106)
at org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher.launch(AMLauncher.java:122)
at org.apache.hadoop.yarn.server.resourcemanager.amlauncher.AMLauncher.run(AMLauncher.java:249)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
. Failing the application.
解決方法如下:
我們的集群有6臺(tái)設(shè)備,在每臺(tái)設(shè)備上使用以下兩條命令考廉。有個(gè)問(wèn)題是秘豹,在執(zhí)行第二條命令的時(shí)候,我在沒(méi)連網(wǎng)的情況下無(wú)法執(zhí)行昌粤,但是在連網(wǎng)的情況下執(zhí)行成功了<热啤!下面是我在itcast01上執(zhí)行的信息涮坐,注意要在其它設(shè)備上也執(zhí)行一下凄贩。
[root@itcast01 ~]# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
cp: overwrite `/etc/localtime'? y
[root@itcast01 ~]# ntpdate pool.ntp.org
29 Oct 11:20:27 ntpdate[2800]: step time server 168.63.242.24 offset -28761.836642 sec
[root@itcast01 ~]#
4.1.4 下面我們便開(kāi)始真正開(kāi)始我們的導(dǎo)入功能即將數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)入到HDFS系統(tǒng)。使用的命令如下紅色字體的內(nèi)容袱讹,我說(shuō)一下命令各項(xiàng)參數(shù)的意思疲扎。
首先./sqoop是我們操作sqoop最常用的命令也是功能最強(qiáng)大的命令。接著捷雕,import是導(dǎo)入的意思椒丧,接著,--connect jdbc:mysql://169.254.254.1:3306意思是以jdbc的方式連接數(shù)據(jù)庫(kù)救巷,169.254.254.1是我們的Windows的IP地址(該IP可以和集群連通)壶熏,3306是端口。接著浦译,sqoop是我們Student表所在的數(shù)據(jù)庫(kù)的名稱(chēng)。接著,--username root --password root 是指數(shù)據(jù)庫(kù)的用戶(hù)名和密碼监署。接著寇损,--table Student意思是我們要導(dǎo)的是Student表。
[root@itcast03 bin]# ./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --table Student
命令的執(zhí)行信息如下圖所示,看到紅色圈住的信息時(shí)說(shuō)明執(zhí)行成功了,這里大家發(fā)現(xiàn)了沒(méi)有,執(zhí)行過(guò)程中只有map甚带,reduce的進(jìn)度始終是0%,說(shuō)明導(dǎo)入功能根本就沒(méi)用到reduce的功能佳头,這個(gè)其實(shí)也好理解鹰贵,我們是要把數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)入到HDFS系統(tǒng),只需要多臺(tái)設(shè)備同時(shí)到數(shù)據(jù)庫(kù)中去讀取一條一條數(shù)據(jù)然后直接上傳到HDFS康嘉,根本就不需要進(jìn)行合并操作碉输。如果是要計(jì)算很多數(shù)的和的話(huà),就要用到reduce了亭珍,顯然我們的導(dǎo)入功能用不到reduce敷钾。
<main style="font-family: "WenQuanYi Micro Hei Mono", "WenQuanYi Micro Hei", "Microsoft Yahei Mono", "Microsoft Yahei", sans-serif, Simsun !important; float: left; width: 840px;">
<article style="font-family: "WenQuanYi Micro Hei Mono", "WenQuanYi Micro Hei", "Microsoft Yahei Mono", "Microsoft Yahei", sans-serif, Simsun !important; box-shadow: rgba(0, 0, 0, 0.0470588) 0px 2px 4px 0px; background-color: rgb(255, 255, 255); padding: 20px 0px;">
4.1.5 執(zhí)行完了導(dǎo)入命令,我們到HDFS系統(tǒng)查看一下生成的結(jié)果肄梨。
我們到狀態(tài)為active的namenode的HDFS界面阻荒,如下圖所示,可以看到itcast02現(xiàn)在是active狀態(tài)众羡,我們點(diǎn)擊"Browse the filesystem"侨赡。
點(diǎn)擊上圖的"Browse the filesystem"鏈接之后我們會(huì)進(jìn)入到如下圖所示的界面,由于我們?cè)趯?dǎo)入的時(shí)候沒(méi)有指定要導(dǎo)入到HDFS的哪個(gè)目錄粱侣,因此系統(tǒng)會(huì)自動(dòng)幫我們存到一個(gè)地方羊壹,它自動(dòng)存的目錄在user文件夾下,如下圖所示齐婴,我們點(diǎn)擊"user"油猫。
點(diǎn)擊上圖的"user"文件夾之后,我們會(huì)進(jìn)入到如下圖所示的界面尔店,由于我們是以root的身份進(jìn)行導(dǎo)入操作的眨攘,因此它自動(dòng)幫我們生成了一個(gè)root文件夾主慰,我們點(diǎn)擊它嚣州。
點(diǎn)擊上圖的"root"文件夾之后,我們會(huì)進(jìn)入到如下圖所示的界面共螺,我們導(dǎo)的是數(shù)據(jù)庫(kù)中的Student表该肴,因此這里生成了一個(gè)叫Student的文件夾,我們點(diǎn)擊它藐不。
點(diǎn)擊上圖的"Student"文件夾之后我們會(huì)鍵入到如下圖所示的界面匀哄,可以看到有4個(gè)結(jié)果文件秦效,也就是說(shuō)使用了4個(gè)mapper來(lái)參與導(dǎo)入操作了,我們還發(fā)現(xiàn)文件的名字中中間都是"m"涎嚼,“m”代表的意思是mapper生成的文件阱州,"r"代表的意思是reducer生成的文件。我們依次點(diǎn)開(kāi)這四個(gè)文件法梯,看看生成的結(jié)果是否正確苔货。
我們先看part-m-00000文件的內(nèi)容,我們點(diǎn)擊上圖的"part-m-00000"鏈接立哑,會(huì)看到如下圖所示的內(nèi)容夜惭,可以看到有三條數(shù)據(jù)信息,列與列之間默認(rèn)是以","分隔的铛绰。
接著我們?cè)賮?lái)看part-m-00001文件的內(nèi)容诈茧,如下圖所示,這個(gè)文件承接上個(gè)文件捂掰,存儲(chǔ)的是ID為4和5的兩條記錄敢会。
接著我們?cè)賮?lái)看看part-m-00002文件的內(nèi)容,如下圖所示尘颓,這個(gè)文件承接上個(gè)文件走触,存儲(chǔ)的是ID為6和7的兩條記錄。
接著我們?cè)賮?lái)看看最后一個(gè)文件part-m-00003文件的內(nèi)容疤苹,如下圖所示互广,該文件承接上個(gè)文件,可以看到有ID為8卧土、9惫皱、10的三條記錄。從而可以得出結(jié)論尤莺,我們剛才的導(dǎo)入操作完全沒(méi)問(wèn)題旅敷。
4.2 我們上面以最簡(jiǎn)單的方式導(dǎo)入了一下數(shù)據(jù),現(xiàn)在我們?cè)俣嗍褂脙蓚€(gè)參數(shù)來(lái)進(jìn)入導(dǎo)入操作颤霎,我們使用的命令如下媳谁,可以看到我們加了兩個(gè)參數(shù),--target-dir(指定要存放到服務(wù)器的哪個(gè)目錄下)和-m(指定要起的mapper的數(shù)量友酱,注意:m前面是一個(gè)"-"晴音,其它參數(shù)前面是兩個(gè)"--",由于用不到reducer合并數(shù)據(jù)缔杉,因此起幾個(gè)mapper就會(huì)生成幾個(gè)文件锤躁。)
[root@itcast03 bin]# ./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --table Student--target-dir /sqoop/td1 -m 2
上面的命令執(zhí)行完之后,我們到服務(wù)器上查看一下生成的結(jié)果或详,我們先到服務(wù)器根目錄下系羞,如下圖所示郭计,可以看到確實(shí)生成了sqoop文件夾,我們點(diǎn)擊進(jìn)入
點(diǎn)擊上圖的sqoop鏈接之后椒振,我們進(jìn)入到如下圖所示的界面昭伸,可以看到確實(shí)有我們剛才命名的td1文件夾,我們點(diǎn)擊進(jìn)入td1澎迎。
點(diǎn)擊上圖的td1鏈接之后勋乾,我們會(huì)看到如下圖所示的界面,可以看到生成了兩個(gè)結(jié)果文件part-m-00000和part-m-00001嗡善,這符合我們?cè)O(shè)置的參數(shù)-m 2的要求辑莫,我們具體看看這兩個(gè)文件中的內(nèi)容。
我們先看看part-m-00000文件中的內(nèi)容罩引,可以看到內(nèi)容是ID從1到5的Student表中的數(shù)據(jù)各吨。
接著我們?cè)倏纯磒art-m-00001文件中的內(nèi)容,可以看到這里面的內(nèi)容是Student表ID從6到10的數(shù)據(jù)袁铐,也完全沒(méi)問(wèn)題=已选!剔桨!
4.3 我們接著來(lái)增加參數(shù)屉更,--fields-terminated-by '\t'意思是指定列與列的分隔符為制表符,--columns 'ID,Name,Age'意思是我們要導(dǎo)入的只有ID洒缀、Name和Age這三列瑰谜。如下所示
[root@itcast03 bin]# ./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --table Student --target-dir /sqoop/td2 -m 2--fields-terminated-by '\t' --columns 'ID,Name,Age'
已經(jīng)截的圖很多了,我就不挨個(gè)截圖了树绩,直接看生成的part-m-00001文件的內(nèi)容吧萨脑,如下圖所示,可以看到列與列之間確實(shí)是用\t來(lái)分隔了饺饭。
4.4 我們現(xiàn)在來(lái)玩一個(gè)更高級(jí)的渤早,我們使用where條件來(lái)篩選數(shù)據(jù)并導(dǎo)入符合條件的數(shù)據(jù),增加的參數(shù)是--where 'ID>=3 and ID<=8'瘫俊,顧名思義鹊杖,就是要把ID從3到8的數(shù)據(jù)導(dǎo)入到服務(wù)器。****
[root@itcast03 bin]# ./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --table Student --target-dir /sqoop/td3 -m 2 --fields-terminated-by '\t' --columns 'ID,Name,Age'--where 'ID>=3 and ID<=8'
** 命令執(zhí)行成功之后扛芽,我們來(lái)看看生成的兩個(gè)文件的內(nèi)容是否符合條件骂蓖,如下圖所示,發(fā)現(xiàn)完全符合我們的where條件胸哥。**
4.5 接下來(lái)我們玩更高級(jí)一點(diǎn)的涯竟,我們使用query語(yǔ)句來(lái)篩選我們的數(shù)據(jù)赡鲜,這意味著我們可以導(dǎo)入多張表的數(shù)據(jù)空厌,我們還是來(lái)個(gè)簡(jiǎn)單的庐船,命令如下。我們發(fā)現(xiàn)使用query語(yǔ)句的話(huà)嘲更,就不用指定table了筐钟,由于數(shù)量很少,現(xiàn)在我們指定mapper的數(shù)量為1赋朦。我們執(zhí)行下面的命令篓冲,該命令目前有個(gè)問(wèn)題。
[root@itcast03 bin]# ./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root--query 'select * from Student where ID>5'--target-dir /sqoop/td4-m 1 --fields-terminated-by '\t'
執(zhí)行上面的命令會(huì)出現(xiàn)如下所示的錯(cuò)誤信息:**must contain '$CONDITIONS' in WHERE clause.**的意思是在我們的query的where條件當(dāng)中必須有**$CONDITIONS'這個(gè)條件宠哄,這個(gè)條件就相當(dāng)于一個(gè)占位符壹将,動(dòng)態(tài)接收傳過(guò)來(lái)的參數(shù),從而查詢(xún)出符合條件的結(jié)果毛嫉。**
16/10/29 18:09:46 ERROR tool.ImportTool: Encountered IOException running import job: java.io.IOException: Query [select * from Student where ID>5]must contain '$CONDITIONS' in WHERE clause.
at org.apache.sqoop.manager.ConnManager.getColumnTypes(ConnManager.java:300)
at org.apache.sqoop.orm.ClassWriter.getColumnTypes(ClassWriter.java:1833)
at org.apache.sqoop.orm.ClassWriter.generate(ClassWriter.java:1645)
at org.apache.sqoop.tool.CodeGenTool.generateORM(CodeGenTool.java:107)
at org.apache.sqoop.tool.ImportTool.importTable(ImportTool.java:478)
at org.apache.sqoop.tool.ImportTool.run(ImportTool.java:605)
at org.apache.sqoop.Sqoop.run(Sqoop.java:143)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:179)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:218)
at org.apache.sqoop.Sqoop.runTool(Sqoop.java:227)
at org.apache.sqoop.Sqoop.main(Sqoop.java:236)
我們?cè)谏厦娴拿钫Z(yǔ)句當(dāng)中加上**$CONDITIONS诽俯,如下所示。然后再執(zhí)行承粤,就可以執(zhí)行成功暴区。**
[root@itcast03 bin]#./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --query 'select * from Student where ID>5 and $CONDITIONS'--target-dir /sqoop/td4 -m 1 --fields-terminated-by '\t'
**執(zhí)行成功后,我們看看結(jié)果文件辛臊,如下圖所示仙粱,發(fā)現(xiàn)確實(shí)導(dǎo)入的是ID從6到10的數(shù)據(jù)。**
假如我們要把-m 1改成-m 2的話(huà)彻舰,導(dǎo)入操作會(huì)失敗伐割,我們來(lái)看一下命令執(zhí)行及異常信息,如下所示刃唤。異常信息的意思是口猜,我們沒(méi)有指定mapper按什么規(guī)則來(lái)分割數(shù)據(jù)。即我這個(gè)mapper應(yīng)該讀取哪些數(shù)據(jù)透揣,一個(gè)mapper的時(shí)候沒(méi)有問(wèn)題是因?yàn)樗粋€(gè)mapper就讀取了所有數(shù)據(jù)济炎,現(xiàn)在mapper的數(shù)量是2了,那么我第一個(gè)mapper讀取多少數(shù)據(jù)辐真,第二個(gè)mapper就讀取第一個(gè)mapper剩下的數(shù)據(jù)须尚,現(xiàn)在兩個(gè)mapper缺少一個(gè)分割數(shù)據(jù)的條件,找一個(gè)唯一標(biāo)識(shí)的一列作為分割條件侍咱,這樣兩個(gè)mapper便可以迅速知道表中一共有多少條數(shù)據(jù)耐床,兩者分別需要讀取多少數(shù)據(jù)。
[root@itcast03 bin]# ./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --query 'select * from Student where ID>5 and $CONDITIONS' --target-dir /sqoop/td5-m 2 --fields-terminated-by '\t'
Please set $ZOOKEEPER_HOME to the root of your Zookeeper installation.
16/10/29 19:01:47 INFO sqoop.Sqoop: Running Sqoop version: 1.4.6
16/10/29 19:01:47 WARN tool.BaseSqoopTool: Setting your password on the command-line is insecure. Consider using -P instead.
When importing query results in parallel, you must specify --split-by.
Try --help for usage instructions
** 知道了異常的原因楔脯,我們便加上分割數(shù)據(jù)的條件撩轰,我們使用的是Student表的ID字段。命令如下。**
[root@itcast03 bin]# ./sqoop import --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --query 'select * from Student where ID>5 and $CONDITIONS' --target-dir /sqoop/td5 -m 2 --fields-terminated-by '\t' --split-by Student.ID
執(zhí)行上面的命令堪嫂,導(dǎo)入操作便可以成功偎箫。如下圖所示。發(fā)現(xiàn)確實(shí)生成了兩個(gè)文件皆串,并且兩個(gè)文件中的內(nèi)容加起來(lái)剛好就是我們query中的條件ID>5淹办。這里我們?cè)僭敿?xì)說(shuō)說(shuō)$CONDITIONS'的作用,sqoop首先根據(jù)Student.ID將數(shù)據(jù)統(tǒng)計(jì)出來(lái)恶复,然后傳給$CONDITIONS'怜森,query語(yǔ)句就知道一共有多條數(shù)據(jù)了,假如第一個(gè)mapper讀取了2條數(shù)據(jù)谤牡,那么也會(huì)把這個(gè)2傳給$CONDITIONS副硅,這樣第二個(gè)mapper在讀取數(shù)據(jù)的時(shí)候便可以根據(jù)第一個(gè)mapper讀取的數(shù)量讀取剩下的內(nèi)容。
第五步:導(dǎo)出
**我們把第四步最后導(dǎo)入的td5文件夾下兩個(gè)文件的數(shù)據(jù)導(dǎo)出到數(shù)據(jù)庫(kù)翅萤。**
** 5.1 我們新建一個(gè)table表想许,這個(gè)table表和我們的Student表結(jié)構(gòu)要一致,在mysql中有一個(gè)復(fù)制表的語(yǔ)句:create table student_copy like Student;這樣我們便可以得到一張表結(jié)構(gòu)和Student完全一樣的表断序,如下圖所示流纹。**
** 5.2 接下來(lái)我們便開(kāi)始將服務(wù)器上的數(shù)據(jù)導(dǎo)出到數(shù)據(jù)庫(kù)中,我們先來(lái)看一個(gè)錯(cuò)誤的命令违诗。**
[root@itcast03 bin]# ./sqoop export --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --export-dir /sqoop/td5 -m 1 --table student_copy
** 錯(cuò)誤信息如下:可以看到是數(shù)據(jù)轉(zhuǎn)換出現(xiàn)了異常漱凝。那么是什么原因?qū)е碌哪兀鋵?shí)是列與列的分隔符導(dǎo)致的诸迟,td5下的兩個(gè)文件中的數(shù)據(jù)是以"\t"來(lái)分隔的茸炒,而sqoop默認(rèn)是以","來(lái)分隔的,因此出現(xiàn)了問(wèn)題阵苇。**
Caused by: java.lang.RuntimeException: Can't parse input data: '6 baiyansong 45 88.0'
at student_copy.__loadFromFields(student_copy.java:335)
at student_copy.parse(student_copy.java:268)
at org.apache.sqoop.mapreduce.TextExportMapper.map(TextExportMapper.java:83)
... 10 more
Caused by: java.lang.NumberFormatException: For input string: "6 baiyansong 45 88.0"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.valueOf(Integer.java:582)
at student_copy.__loadFromFields(student_copy.java:317)
... 12 more
知道了問(wèn)題壁公,我們對(duì)癥下藥,人為指定分隔符--fields-terminated-by '\t'绅项,命令如下所示紊册。這里說(shuō)明一點(diǎn)的是,--export-dir /sqoop/td5這個(gè)參數(shù)有些人可能會(huì)有疑惑,因?yàn)閠d5文件夾下除了part-m-00000和part-m-00001兩個(gè)結(jié)果文件外快耿,還有一個(gè)名為“SUCCESS”的文件囊陡,導(dǎo)出的時(shí)候會(huì)不會(huì)連這個(gè)文件的內(nèi)容都導(dǎo)出去了呢?其實(shí)不會(huì)的掀亥,我們指定到文件夾撞反,程序會(huì)去掃描這個(gè)文件夾下的所有文件,凡是不以""開(kāi)頭的文件都會(huì)被導(dǎo)出去搪花,SUCCESS文件是以“”開(kāi)頭的遏片,因此它不會(huì)被導(dǎo)出去嘹害,大家放心。
[root@itcast03 bin]#./sqoop export --connect jdbc:mysql://169.254.254.1:3306/sqoop --username root --password root --export-dir /sqoop/td5 -m 1 --table student_copy--fields-terminated-by '\t'
** 執(zhí)行成功后我們看看我們剛才復(fù)制的student_copy表中是否有了我們導(dǎo)出的數(shù)據(jù)吮便。發(fā)現(xiàn)確實(shí)導(dǎo)出到數(shù)據(jù)庫(kù)5條數(shù)據(jù)笔呀,這5條數(shù)據(jù)也就是td5下面兩個(gè)文件的內(nèi)容,說(shuō)明我們的導(dǎo)出功能也完全正常O呱馈!**