data exchange
更新日期:
本文将介绍一下常见的几种数据交换的场景,及解决方法
1.不同集群之间 hdfs 文件 或 hive表 迁移
2.利用sqoop实现按日增量导入,及状态表的全量覆盖
环境准备
- hadoop2
- sqoop-1.4.6.bin__hadoop-2.0.4-alpha
- hive
hive表集群间迁移
利用hadoop distcp命令,例如把hive 的 test库下的g_info表导入到数据目录下,如果仅仅是文件拷贝而不涉及hive表,则这一条命令就可以了
1 | hadoop distcp hdfs://192.168.1.169:9000/user/hive/warehouse/test.db/t1 hdfs://192.168.7.11:9000/user/hive/warehouse/test.db/t1_cp |
hive表是非分区表
1.先创建「外部表」
1 | CREATE external TABLE t1_cp( |
2.通过load data的方式加载数据
1 | LOAD DATA INPATH 'hdfs://192.168.7.11:9000/user/hive/warehouse/test.db/t1_cp/' INTO TABLE t1_cp; |
hive是分区表
1.如果hive是分区表,则迁移复制过来的目录结构应该带「分区文件夹」的,所以不能直接一次性导入,因此需要先创建「外部表」且添加「分区信息」,去掉「数据目录」
1 | CREATE external TABLE t1_cp( |
2.利用 hadoop distcp
命令把数据复制到 hive show create table t1_cp
下的 location 数据目录下
3.由于一个表的分区信息可能很多,甚至几千个,所以需要用脚本自动化来实现「添加分区」及「导入数据」的过程 (注意:根据自己的实际情况,修改路径及 awk截取字符串的位置)
1 | #!/bin/sh |
4.执行脚本 nohup sh your.sh &
sqoop 导入数据
一般我们的导入,有「全量覆盖」或「按日新增」 两种方式,而这2种方式,都要先做两件事情
1.创建内部表,如果是「按日增量」则需要添加 partition 语句
1 | CREATE TABLE t1_cp( |
2.建立分区
1 | alter table t1_cp ADD PARTITION (pdt='2015-12-12'); |
3.执行sqoop导入命令
无分区
注:下面是一行命令1 | sqoop import --connect "jdbc:mysql://127.0.0.1:3306/test" --username sqoop --password sqoop \ |
重要参数说明
--query
代表需要执行的sql语句,其中需要硬性添加一个$CONDITIONS
变量,注意shell环境$符号需要转义--target-dir
代表sqoop执行mr完后的输出目录,跟query成对出现--delete-target-dir
代表每次删除目录,然后重新覆盖导入--fields-terminated-by
字段间分隔符--m
代表mapreduce中 map 个数
分区表
注:下面是一行命令1 | sqoop import --connect "jdbc:mysql://127.0.0.1:3306/test" --username sqoop --password sqoop \ |
重要参数说明
--append
追加模式,不会增量,仅仅增加数据文件。因此需要用sql控制增量- 不要添加
--delete-target-dir
其他
1.有些数据库,会有中文的问题,需要在sql中添加转义,例如
1 | convert(binary convert(title using latin1) using gbk) as title |
2.sqoop会用 hadoop-env.sh
里配置的 $JAVA_HOME
指向的 jdk,而不会关心系统环境变量
3.如果需要自动化,可以利用shell获取时间,然后每日crontab导入
后记补充
问题一: 最近 使用hive表的字段时,发现错位了
原因是字段内容本身有 \t 字符,然后删除表,设定sqoop脚本为 \001 字符,然后创建hive表分割字符为 \001 换行符也是一样(hive只支持\n)
可以添加 --hive-drop-import-delims
(Drops \n, \r, and \01 from string fields when importing to Hive.)参数
问题二: 导出数据会自动把 数字0 和非零 mysql 数据,转换到hive 为 true false
引用自:http://www.cnblogs.com/cenyuhai/archive/2013/09/06/3306073.html
jdbc会把 tinyint(1)认为是 java.sql.Types.BIT ,然后sqoop就会转为Boolean了
解决方法1:
- 在连接上加上一句话 tinyInt1isBit=false 例如 jdbc:mysql://localhost/test?tinyInt1isBit=false
解决方法2:
- hive使用 –map-column-hive foo=tinyint
- 非hive使用–map-column-java foo=integer