数据仓库之Sqoop Import

Posted 小数据自留地

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据仓库之Sqoop Import相关的知识,希望对你有一定的参考价值。

最近在准备接手外部的一个老的数仓平台,准备基于HADOOP进行重构,重构的第一步是从外部系统中导入数据到数据仓库, 正好趁此机会重新学习下Sqoop Import, 后文的讲解也主要是基于官方文档的一个总结和提炼。



Sqoop的主要功能是从传统的关系型数据库mysql,Oracle导入和导出数据到Hadoop平台,类似功能的工具还有kettle, 因为我们使用的CDH平台搭建的数仓,Sqoop基本可以一键安装,所以选择了Sqoop。

Sqoop是利用MapReduce导入和导出数据, 它会将数据库表中的数据一列列的(row-by-row)写入HDFS中, 也就是Sqoop的输出实际上是一堆包含数据表内容的文件。前文提到Sqoop导入到Hadoop平台,是因为其实在指定导入数据的输出的时候,不仅支持HDFS, 还可以直接导入到Hive,Hbase, 等。 但其实Hive底层的数据仍然存储在HDFS中,只是Sqoop还可以完成Hive建表,Metastore的操作, 这样更简化了Sqoop与Hive等数仓系统的对接。



现在先来看看Sqoop Import这一块最重要的2个命令:

  • Import:Import a table from a database to HDFS

  • Import-all-tables:  Import tables from a database to HDFS

可以看到Sqoop支持单表导入或者整个库的导入,但日常工作中单步的导入用的是最多的。Sqoop的输出可以指定Hdfs的路径,或者指定Hive表名, 下面会有几个代码例子进行分别讲解。



Sqoop导入到HDFS:

$ sqoop import --connnect <connect-str> --table foo --target-dir /dest \

这是一个官方文档的基本例子,这里直接指定将foo这个表导入到--target-dir所指定的HDFS目录中, 这里还可以添加--columns参数来选择所需要的导入的列。

但在实际生产环境中我们使用更多是Hive的分区表,每天同步当天更新的数据,不会像上面个例子一样每天全表导入,还可能有些where条件, 这时候就需要用--query(free-form query imports)参数:

/usr/bin/sqoop import -D map.retry.numRetries=3 \--connect jdbc:mysql://$DB_CNX?tinyInt1isBit=false \--username $USERNAME \--password $PASSWORD \--target-dir $TARGET_DIR \--delete-target-dir \--num-mappers 1 \--fields-terminated-by "\t" \--query "$IMPORT_QUERY"
  • --query "$IMPORT_QUERY" 这里填写需要的select sql,  使用这种query的时候必须同时使用参数target-dir来指定相应的Hdfs目录

  • --delete-target-dir:这个是会先删除已经存在的target-dir指定的hdfs文件目录, 这样保证了该sqoop import可以重复执行。否则的话会把文件append到该目录下,每执行一次会产生一份重复数据

  • --num-mappers:指定import的map tasks的个数, 一般情况下在数据量不太大的情况下其实定义为1即可,做过测试发现,如果小数据情况下使用多个maps会更慢, 可能因为多个map tasks启动也需要时间。

  • --fields-terminated-by:这是指定表中列的分隔符的参数, 这个设为什么很重要,如果数据中本身有\t, 再设分隔符为\t就会导致数据列数据出现问题, 之前在采集日志数据时踩过这个坑

  • 这里看到设置数据库JDBC连接时有个tinyInt1isBit=false的设置, 这是因为tinyint 类型通过sqoop 抓取出来的数据在HDFS 上面显示的true、false, 配置这个参数会保持原有的数字类型


除了这几个参数以外,这里还想提一下另外二个比较重要的参数

  • --as-textfile : 这里是为了指定HDFS文件的格式,textfile这个是HDFS默认的保存格式,也就是说不指名参数的情况下,数据会保存为textfile, 其他还支持--as-sequencefile,--as-parquetfile等 。对于Hive表来说,textfile并不是太好的选择,可以考虑在ORC或者Parquet格式中进行选择,但是目前sqoop没有提供--as-orc这样的参数,如果选择这种方式导入数据,选择Parquet格式会更方便。如果想保存为ORC的话,需要使用另外一种方法,后文会进行讲解。

  • --compress: 开启压缩,默认的话是不开启压缩的, 这里还可以通过--compression-codec指定压缩格式, 默认格式为gzip。


做过一个初步测试,一个mysql的表数据同步过来,使用默认textfile进行同步并且不设置压缩,文件大小100M,如果存储为ORC并启用默认的gzip压缩后文件大小仅为5M,也就是说能很轻松的获得95%的压缩率,对于数据量很大的表来说还是很有必要在sqoop导入数据时,好好设置这2个参数。

基于以上的命令我们只是将数据放在HDFS中,但数据仓库,我们实际操作的是Hive,后面还需要使用Hive命令将HDFS中的文件导入到Hive表中, 这样才算是完成将mysql等传统的关系型数据库导入到Hive这样的数据仓库中。

 sql="load data inpath '$TARGET_DIR' OVERWRITE into table $HIVE_TABLE partition(dt='$DB_DATE');"  hive -e "$sql"



其实Sqoop还提供一个 --hive-import 的参数,可以在导入数据后在Hive中自动建表。官方文档的例子如下

 sqoop import --connect jdbc:mysql://db.foo.com/corp --table EMPLOYEES \ --hive-import

如果你的Hive表已经存在,还可以使用-hive-overwrite去覆盖当前表。也就是说使用--hive-import 的参数, 会自动执行"CREATE TABLE" 和 "LOAD DATA INPATH " 这二步,直接将数据写入Hive中。

从这里来看, --hive-import还是挺有用的,但我实际在生产中使用的比较少,因为自动生成的create table的字段类型并不一定是最优解, 还有就是生产环境大量是按日分区表, 需要每天添加新分区数据,但并不希望重新建表,所以使用之前提到的导入数据到HDFS在进行LOAD的方法会更合适一点。--hive-import 这样的参数还是可以用来进行初次的建表,比如获得Hive表结构信息, 然后再优化字段, 避免手动的从Mysql等数据库中获取。



到这里为止我们基本可以用Sqoop满足从传统关系型数据库导入数据到HDFS或者Hive中的需求,但这里还有一个问题就是Sqoop只支持导入为textfile、avrofile、sequencefile等格式, 如果需要将数据导入为ORC格式,需要先导出临时表,再通过Hive转换,这时候我们可以利用HCatalog来解决这个问题。


首先HCatalog是一个单独的Hadoop的表存储管理工具。它将Hive Metastore的表格数据公开给其他Hadoop应用程序。使得具有不同数据处理工具(MapReduce)的用户能够轻松将数据写入网格, 确保用户不必担心数据存储在何处或以何种格式存储。


Sqoop在集成了Hcatalog后, 能够存储文件为RCFile等文件格式,解决了我们之前无法将文件存为ORC的问题。这里还是一个例子进行讲解:

/usr/bin/sqoop import -D map.retry.numRetries=3 \--connect jdbc:mysql://$DB_CNX?tinyInt1isBit=false \--username $USERNAME \--password $PASSWORD \--hcatalog-database $HIVE_DB\--hcatalog-table $HIVE_TABLE \--hcatalog-partition-keys $KEY \--hcatalog-partition-values $DB_DATE \--num-mappers 1 \--compress \--query "$IMPORT_QUERY"}

这里可以看到需要在参数中指定Hive的库和表,还可以指定Hive的分区key和值, 这里也可以使用--hive-partition-key和--hive-partition-value, 这样Sqoop会自动导入成Hive表本身指定的数据格式。同样也可以使用 --create-hcatalog-table 参数进行hive的建表,这点和--hive-import 类似。 


这里需要注意的是,使用hcatalog后,有些sqoop的参数就不再支持,比如:--hive-import, --hive-overwrite, --target-dir, --as-sequencefile, 完整的不再支持的参数列表还需去查阅官方文档。这里需要注意的是使用hcatalog后,没有办法在overwrite之前导入的数据,也不支持--target-dir 和--delete-target-dir, 这样我们重复跑相同的脚本数据会叠加在同一个目录下,我们展示使用的是HDFS命令强制清理数据,然后再调用sqoop import命令。



总体来说,Sqoop import是为了从传统关系型数据库Mysql等中导入数据到HDFS, 下面列举下几个主要命令的特点的和使用场景:

  • sqoop import:最简单的import方式,将数据直接导入到指定的HDFS目录中,通过--delete-target-dir参数可以反复执行同一脚本, 而且可以定制存储除了ORC以外的HDFS的格式, 如果是要写入Hive,还需要使用LOAD DATA 命令。

  • sqoop import --hive-import :继承上面sqoop import的一些基本参数,而且会自动执行"CREATE TABLE" 和 "LOAD DATA INPATH " 这二步,直接将数据写入Hive中。比较适合第一次建表的,但不适合需要经常同步的分区表等。

  • sqoop import --hcatalog-database:使用Hcatalog的最大好处是可以直接对接Hive表,而且会按Hive定义的数据格式写入数据,而且支持ORC,唯一的问题是不支持overwrite反复写入。比较适合我们在先期建好了Hive的表,设定好表的文件存储格式


最后一点自己的心得,刚刚开始使用sqoop的时候网上搜到了几个例子,就开始写脚本,然后发现了问题以后再baidu,google,这一次通读了官方文档发现很多问题官方文档都给出了明确的说明和解答, 还是要注重官方文档的阅读,比自己胡乱搜索来的更有价值。



以上是关于数据仓库之Sqoop Import的主要内容,如果未能解决你的问题,请参考以下文章

sqoop之hive数据仓库和oracle数据库数据转换

sqoop的使用之import导入到HDFS

hadoop生态之sqoop

数据仓库 Azkaban调度器

使用 sqoop 将mysql数据导入到hive(import)

Hive数仓项目之sqoop相关操作访问咨询主题看板_全量流程