Sqoop - 数据库离线数据采集工具使用详解2(样例1:Mysql数据导入HDFS)
作者:hangge | 2024-04-09 09:11
二、实现将 Mysql 数据导入HDFS
1,准备工作
(1)为了演示如何将 MySQL 中指定表的数据导入 HDFS 中,首先我们在 MySQL 中创建一张 user 表:
(2)接着在该表中插入 4 条数据:
(2)控制台输出如下内容说明任务执行完毕:
(3)看到 HDFS 上也创建了对应的目录和文件:
(4)打开文件可以看到里面便是从数据库中导出的数据:
(2)查看 HDFS 上的文件,里面内容只有复合查询条件的数据:
CREATE TABLE `user` ( `id` int(10) NOT NULL AUTO_INCREMENT, `name` varchar(64) DEFAULT NULL, `phone` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`) );
(2)接着在该表中插入 4 条数据:
INSERT INTO user (id, name, phone) VALUES ('1', 'lilei', null); INSERT INTO user (id, name, phone) VALUES ('2', 'xiaoliu', '888888'); INSERT INTO user (id, name, phone) VALUES ('3', 'hangge', '123456'); INSERT INTO user (id, name, phone) VALUES ('4', 'baidu', null);
2,全表导入样例
(1)下面命令使用 Sqoop 将表 user 中的数据导入 HDFS 中:(1)如果表 user 中没有主键,并且 Sqoop 命令中也没有设置 --num-mappers 1,则下面的 Sqoop 命令执行会报错,因为 MapReduce 任务中的 Map 任务数默认是 4,需要分 4 个 Map 任务,每个 Map 任务计算一部分数据,但是表 user 没有主键,所以 MapReduce 不知道以哪个字段为基准来拆分数据。
(2)解决办法可以选择下面其中一种:
- 在表中设置主键,默认根据主键字段拆分数据。
- 使用 --num-mappers 1,表示将 Map 任务个数设置为 1,这样就不需要拆分数据了。
- 使用 --split-by,后面指定一个数字类型的列,MapReduce 会根据这个列拆分数据。
sqoop import \ --connect jdbc:mysql://192.168.60.1:3306/hangge?serverTimezone=UTC \ --username root \ --password hangge1234 \ --table user \ --target-dir /out1 \ --delete-target-dir \ --num-mappers 1 \ --fields-terminated-by '\t'
(2)控制台输出如下内容说明任务执行完毕:
3,查询导出样例
(1)下面命令使用 SQL 语句查询表中满足条件的数据(id>1)并将其导入 HDFS 中。
注意:
- 在使用 --query 指定 SQL 语句时,其中必须包含 $CONDITIONS。
- --query 和 --table 这两个参数不能在一个 Sqoop 命令中同时指定。
sqoop import \ --connect jdbc:mysql://192.168.60.1:3306/hangge?serverTimezone=UTC \ --username root \ --password hangge1234 \ --target-dir /out2 \ --delete-target-dir \ --num-mappers 1 \ --fields-terminated-by '\t' \ --query 'select id,name,phone from user where id >1 and $CONDITIONS;'
(2)查看 HDFS 上的文件,里面内容只有复合查询条件的数据:
4,NULL 值处理样例
(1)在默认情况下,MySQL 中的 NULL 值(无论字段类型是字符串类型还是数字类型)在使用 Sqoop 导入 HDFS 后会显示为字符串 null。
(2)我们可以通过参数来设置NULL值的替换方式:
- 对于字符串的 NULL 类型:通过 --null-string '*' 来指定。在单引号中指定字符串,这个字符串不能是 --,因为 -- 是保留关键字。
- 对于非字符串的 NULL 类型:通过 --null-non-string '=' 来指定。在单引号中指定字符串,这个字符串不能是 --,因为 -- 是保留关键字。
注意:
- 这两个参数可以同时设置,这样在做数据导入时,空值字段会被替换为指定的字符串内容。
- 在 --null-string 和 --null-non-string 后面指定字符串时不能使用双引号,只能使用单引号,否则执行会报错,Sqoop 对引号是比较敏感的。
(3)举例来说,假设我们将数据导入 HDFS 后最终是希望在 Hive 中进行查询,那么久可以使用 "\N" 表示 NULL值。因为 Hive 对于NULL 值在底层数据文件中是使用 “\N” 存储的。
sqoop import \ --connect jdbc:mysql://192.168.60.1:3306/hangge?serverTimezone=UTC \ --username root \ --password hangge1234 \ --target-dir /out3 \ --delete-target-dir \ --num-mappers 1 \ --fields-terminated-by '\t' \ --query 'select id,name,phone from user where id >1 and $CONDITIONS;' \ --null-string '\\N' \ --null-non-string '\\N'
(4)上面任务执行完毕后,可以看到 HDFS 文件中数据的 NULL 值都被替换成 \N:
5,封装 Sqoop 脚本
(1)在工作中使用 Sqoop 时,建议将 Sqoop 的命令写在 Shell 脚本中,否则无法实现命令重用,并且调用也不方便。比如,我们执行如下命令创建一个在 Shell 脚本:
vi sqoop-import-user.sh
(2)脚本内容如下:
#!/bin/bash sqoop import \ --connect jdbc:mysql://192.168.60.1:3306/hangge?serverTimezone=UTC \ --username root \ --password hangge1234 \ --target-dir /out3 \ --delete-target-dir \ --num-mappers 1 \ --fields-terminated-by '\t' \ --query 'select id,name,phone from user where id >1 and $CONDITIONS;' \ --null-string '\\N' \ --null-non-string '\\N'
(3)使用时执行如下命令即可:
./sqoop-import-user.sh
附:Sqoop 常见参数
1,通用参数
参数 | 解释 |
--connect <jdbc-uri> | 指定 JDBC 连接字符串 |
--connection-manager <class-name> | 指定要使用的连接管理器类 |
--driver <class-name> | 指定要使用的 JDBC 驱动类 |
--hadoop-mapred-home <dir> | 指定 HADOOP_MAPRED_HOME 路径 |
--help | 帮助 |
--password-file | 设置用于存放认证的密码信息文件的路径 |
-P | 从控制台读取输入的密码 |
--password <password> | 设置认证密码 |
--username <username> | 设置认证用户名 |
--verbose | 打印详细的运行信息 |
--connection-param-file <filename> | 指定存储数据库连接参数的属性文件 |
2,数据导入相关参数数
参数 | 解释 |
--append | 将数据追加到 HDFS 上一个已存在的数据集中 |
--as-avrodatafile | 将数据导入 Avro 数据文件 |
--as-sequencefile | 将数据导入 SequenceFile |
--as-textfile | 将数据导入普通文本文件(默认) |
--boundary-query <statement> | 边界查询,用于创建分片(InputSplit) |
--columns <col,col,col…> | 从表中导出指定的一组列的数据 |
--delete-target-dir | 如果指定目录存在,则先将其删除 |
--direct | 使用直接导入模式(优化导入速度) |
--direct-split-size <n> | 指定切分输入数据的大小(在直接导入模式下) |
--fetch-size <n> | 从数据库中批量读取记录数 |
--inline-lob-limit <n> | 设置内联的 LOB 对象的大小 |
-m,--num-mappers <n> | 使用 n 个 map 任务并行导入数据 |
-e,--query <statement> | 导入的查询语句 |
--split-by <column-name> | 指定按照哪个列去切分数据 |
--table <table-name> | 导入的源表表名 |
--target-dir <dir> | 导入 HDFS 的目标路径 |
--warehouse-dir <dir> | HDFS 存放表的根路径 |
--where <where clause> | 指定导出时所使用的查询条件 |
-z,--compress | 启用压缩 |
--compression-codec <c> | 指定 Hadoop 的压缩方式(默认为 Gzip) |
--null-string <null-string> | 使用指定字符串,替换字符串类型值为 null 的列 |
--null-non-string <null-string> | 使用指定字符串,替换非字符串类型值为 null 的列 |
3,数据导出相关参数数
参数 | 解释 |
--direct | 使用直接导出模式(优化速度) |
--export-dir <dir> | 导出过程中 HDFS 的源路径 |
--m,--num-mappers <n> | 使用 n 个 map 任务并行导出 |
--table <table-name> | 导出的目的表名称 |
--call <stored-proc-name> | 导出数据调用的指定存储过程名 |
--update-key <col-name> | 更新参考的列名称,多个列名之间使用逗号分隔 |
--update-mode <mode> | 指定更新策略,包括 updateonly(默认)、allowinsert |
--input-null-string <null-string> | 使用指定字符串,替换字符串类型值为 null 的列 |
--input-null-non-string <null-string> | 使用指定字符串,替换非字符串类型值为 null 的列 |
--staging-table <staging-table-name> | 在数据导出到数据库之前,数据临时存放的表名称 |
--clear-staging-table | 清除工作区中临时存放的数据 |
--batch | 使用批量模式导出 |
全部评论(0)