1.Sqoop安装
下载sqoop文件:
[hadoop@hadoop001 software]$ wget http://archive.cloudera.com/cdh5/cdh/5/sqoop-1.4.6-cdh5.7.0.tar.gz
解压:
[hadoop@hadoop001 software]$ tar -zxvf sqoop-1.4.6-cdh5.7.0.tar.gz -C ~/app/sqoop-1.4.6-cdh5.7.0
配置环境变量
[hadoop@hadoop001 sqoop-1.4.6-cdh5.7.0]$ vim ~/.bash_profile
export SQOOP_HOME=/home/hadoop/app/sqoop-1.4.6-cdh5.7.0
export PATH=$SQOOP_HOME/bin:$PATH
生效文件:
[hadoop@hadoop001 sqoop-1.4.6-cdh5.7.0]$ source ~/.bash_profile
复制配置文件
[hadoop@hadoop001 conf]$ cp sqoop-env-template.sh sqoop-env.sh
修改环境配置文件
[hadoop@hadoop001 conf]$ vim sqoop-env.sh
export HADOOP_COMMON_HOME=/home/hadoop/app/hadoop-2.6.0-cdh5.7.0
export HADOOP_MAPRED_HOME=/home/hadoop/app/hadoop-2.6.0-cdh5.7.0
export HIVE_HOME=/home/hadoop/app/hive-1.1.0-cdh5.7.0
需要将mysql相应的jar包,放入到sqoop的目录下
[hadoop@hadoop001 lib]$ cp ~/app/hive-1.1.0-cdh5.7.0/lib/mysql-connector-java-5.1.27.jar .
2.sqoop导入(MySQL==>HDFS)
使用sqoop展示所有的数据库:
[hadoop@hadoop001 bin]$ sqoop list-databases --connect jdbc:mysql://localhost:3306 --username root --password 123456
展示数据库中的数据表
[hadoop@hadoop001 bin]$ sqoop list-tables --connect jdbc:mysql://localhost:3306/sqoop --username root --password 123456
dept
emp
salgrade
插入相关的表和数据
create table emp (
empno numeric(4) not null,
ename varchar(10),
job varchar(9),
mgr numeric(4),
hiredate datetime,
sal numeric(7, 2),
comm numeric(7, 2),
deptno numeric(2)
);
insert into emp values (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, null, 20);
insert into emp values (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600, 300, 30);
insert into emp values (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30);
insert into emp values (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, null, 20);
insert into emp values (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30);
insert into emp values (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, null, 30);
insert into emp values (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, null, 10);
insert into emp values (7788, 'SCOTT', 'ANALYST', 7566, '1982-12-09', 3000, null, 20);
insert into emp values (7839, 'KING', 'PRESIDENT', null, '1981-11-17', 5000, null, 10);
insert into emp values (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500, 0, 30);
insert into emp values (7876, 'ADAMS', 'CLERK', 7788, '1983-01-12', 1100, null, 20);
insert into emp values (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, null, 30);
insert into emp values (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, null, 20);
insert into emp values (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, null, 10);
create table salgrade (
grade numeric,
losal numeric,
hisal numeric
);
insert into salgrade values (1, 700, 1200);
insert into salgrade values (2, 1201, 1400);
insert into salgrade values (3, 1401, 2000);
insert into salgrade values (4, 2001, 3000);
insert into salgrade values (5, 3001, 9999);
create table dept (
deptno numeric(2),
dname varchar(14),
loc varchar(13)
);
insert into dept values (10, 'ACCOUNTING', 'NEW YORK');
insert into dept values (20, 'RESEARCH', 'DALLAS');
insert into dept values (30, 'SALES', 'CHICAGO');
insert into dept values (40, 'OPERATIONS', 'BOSTON');
导出数据
[hadoop@hadoop001 bin]$ sqoop import --connect jdbc:mysql://localhost:3306/sqoop --username root --password 123456 --table emp
出现错误:Exception in thread "main" java.lang.NoClassDefFoundError: org/json/JSONObject
需要下载文件java-json.jar文件
[hadoop@hadoop001 lib]$ pwd
/home/hadoop/app/sqoop-1.4.6-cdh5.7.0/lib
[hadoop@hadoop001 lib]$ wget http://www.java2s.com/Code/JarDownload/java-json/java-json.jar.zip
解压文件
[hadoop@hadoop001 lib]$ unzip java-json.jar.zip
产生数据的放在HDFS的根目录下,并以数据表的表明为文件夹名,如果没有数据,设置为空。
查看数据:
[hadoop@hadoop001 ~]$ hadoop fs -ls /user/hadoop
drwxr-xr-x - hadoop supergroup 0 2018-11-12 23:54 /user/hadoop/emp
在指定导入数据时,默认为分成4个map: mapreduce.JobSubmitter: number of splits:4,也可以指定map和reduce的数量。
[hadoop@hadoop001 ~]$ hadoop fs -ls /user/hadoop/emp
-rw-r--r-- 1 hadoop supergroup 0 2018-11-12 23:54 /user/hadoop/emp/_SUCCESS
-rw-r--r-- 1 hadoop supergroup 124 2018-11-12 23:54 /user/hadoop/emp/part-m-00000
-rw-r--r-- 1 hadoop supergroup 126 2018-11-12 23:54 /user/hadoop/emp/part-m-00001
-rw-r--r-- 1 hadoop supergroup 253 2018-11-12 23:54 /user/hadoop/emp/part-m-00002
-rw-r--r-- 1 hadoop supergroup 368 2018-11-12 23:54 /user/hadoop/emp/part-m-00003
在执行的过程中,要保证文件不存在,如果存在,需要删除,也可以添加参数--delete-target-dir,就不会报错啦。
设置生成作业的名称以及map的个数,使用参数 -m:
[hadoop@hadoop001 bin]$sqoop import --connect jdbc:mysql://localhost:3306/sqoop --username root --password 123456 --table emp --mapreduce-job-name FromMySQLToHDFS -m 1
#如果多次导出同一个表时,就会有FileExsitsException。需要添加参数--delete-target-dir,即
[hadoop@hadoop001 bin]$sqoop import --connect jdbc:mysql://localhost:3306/sqoop --username root --password 123456 --table emp --mapreduce-job-name FromMySQLToHDFS -m 1 --delete-target-dir
如果需要导出一个表的几个字段时,并且将没有数据进行填充,使用--columns 参数,指定字段,也可以指定要导出的位置,使用参数--target-dir,判断一些空的值或者null值,并制定值,使用--null-non-string,--null-string,也可以添加查询的参数,使用--where,在输出的数据中,为了好看,需要添加字符分隔符,参数为--fields-terminated-by,需要使用下面的命令:
[hadoop@hadoop001 bin]$ sqoop import --connect jdbc:mysql://localhost:3306/sqoop --username root --password 123456 --table emp --mapreduce-job-name FromMySQLToHDFS -m 1 --delete-target-dir --columns 'EMPNO,ENAME,JOB,SAL,COMM' --target-dir EMP_COLUMN_WHERE --fields-terminated-by '\t' --null-non-string '0' --null-string '' --where 'SAL>2000'
使用一个完整的查询语句替换,上面的操作,使用参数 -e, 语句如下:
[hadoop@hadoop001 bin]$sqoop import \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--mapreduce-job-name FromMySQLToHDFS \
-m 1 \
--delete-target-dir \
--target-dir EMP_COLUMN_QUERY \
--fields-terminated-by '\t' \
--null-non-string '0' \
--null-string '' \
-e 'select * from emp where empno>7900'
如果使用这个语句,会有一个错误,ERROR tool.ImportTool: Encountered IOException running import job: java.io.IOException: Query [select * from emp where empno>7900] must contain '$CONDITIONS' in WHERE clause.
通过错误信息,可以看到,需要添加一个$CONDITIONS字符串,--table与-e-同时使用,会出现歧义的问题,需要使用其他方法来解决,例如增加在sql语句中必须要在条件加上$CONDITIONS,如下所示:
[hadoop@hadoop001 bin]$sqoop import \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--mapreduce-job-name FromMySQLToHDFS \
-m 1 \
--delete-target-dir \
--target-dir EMP_COLUMN_QUERY \
--fields-terminated-by '\t' \
--null-non-string '0' \
--null-string '' \
-e 'select * from emp where empno>7900 and $CONDITIONS'
#如果将单引号换成双引号时,会出现错误,要对$进行转移
[hadoop@hadoop001 bin]$sqoop import \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--mapreduce-job-name FromMySQLToHDFS \
-m 1 \
--delete-target-dir \
--target-dir EMP_COLUMN_QUERY \
--fields-terminated-by '\t' \
--null-non-string '0' \
--null-string '' \
-e "select * from emp where empno>7900 and \$CONDITIONS"
#在数据表中的数据导出时,没有设置主键时,就会出现错误:Error during import:No primary key could be found for table.please specify one with --split-by or perform a sequential import with '-m 1',可以指定按照那个字段来进行拆分或者使用一个map来进行处理。可以使用下面的语法:
[hadoop@hadoop001 bin]$sqoop import \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--table salgrade \
--split-by GRADE \
-m 2
可以将执行写入一个文件中,添加--options-file参数,--options-file 可以直接执行某个文件,将一下常用的操作封装到一个文件中。
[hadoop@hadoop001 bin]$sqoop --options-file /home/hadoop/data/import.txt
文件内容为:
import
--connect
jdbc:mysql://localhost:3306/sqoop
--username
root
--password
123456
--table
emp
--delete-target-dir
在编写--options-file文件时,需要注意的是,不要有sqoop关键字,将'\'去掉,写成KV的形式。
3.导出(HDFS==>MySQL)
将hadoop中的数据导入到mysql中:
[hadoop@hadoop001 bin]$sqoop export \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--table emp_test \
--export-dir emp
输出错误信息:Error executing statement: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'sqoop.emp_test' doesn't exist com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'sqoop.emp_test' doesn't exist
这是由于emp_test数据表不存在sqoop数据库中,需要添加创建这个数据表,创建命令如下:
mysql> create table emp_test as select * from emp where 1=2;
然后在执行上面的命令,可以查看到数据已经导入了。
在导出数据库时,有时会只需要几个字段,可以使用下面的命令:
[hadoop@hadoop001 bin]$sqoop export \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--table emp_test \
--export-dir emp \
--columns 'EMPNO,ENAME,JOB,SAL,COMM'
控制台会输出:ERROR tool.ExportTool: Error during export: Export job failed!,这是由于没有分割符或者分隔符不对造成的,修改命令如下:
[hadoop@hadoop001 bin]$sqoop export \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--table emp_test \
--export-dir emp \
--columns 'EMPNO,ENAME,JOB,SAL,COMM' \
--fields-terminated-by '\t'
4.MySQL==>Hive
在导入数据时,需要在Hive上创建数据表(在default下创建),命令如下:
CREATE TABLE emp_test (
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
common double,
deptno int
)ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
也可以在导入的时候,指定要创建的数据表,可以对数据库的数据进行重写,命令如下:
[hadoop@hadoop001 bin]$sqoop import \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--table emp \
--delete-target-dir \
--hive-import \
--hive-table emp_test \
--fields-terminated-by '\t' \
--columns 'empno,ename,job,sal,common' \
--hive-overwrite
在mysql==>hive的过程中,有的需要导入到指定数据库中,如果没有指定数据库,默认导入到default数据下,在查看是否导入成功时,需要到/user/hive/warehouse文件夹下查看,可以添加参数--hive-database 来指定要导入的数据库。
创建分区表:
CREATE TABLE emp_test_p (
empno int,
ename string,
job string,
mgr int,
hiredate string,
sal double,
common double,
deptno int
)partitioned by (pt string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
导入的命令:
[hadoop@hadoop001 bin]$sqoop import \
--connect jdbc:mysql://localhost:3306/sqoop \
--username root \
--password 123456 \
--table emp \
--delete-target-dir \
--hive-import \
--hive-table emp_test_p \
--fields-terminated-by '\t' \
--columns 'empno,ename,job,sal,common' \
--hive-overwrite \
--hive-partition-key 'pt' \ #指定分区字段
--hive-partition-value 'xiaoyao' #指定分区值
在导入之后,可以在hive中直接看数据:
hive (default)> select * from emp_test_p where pt='xiaoyao';
在导入的时候,会出现ClassNotFoundException:org.apache.hive.conf.HiveConf异常,这是因为没有配置HIVE_CONF_DIR,但是配置HIVE_CONF_DIR变量之后,依然爆相应的错误,需要将相应的文件包复制到sqoop中
hadoop@hadoop001 lib]$ pwd
/home/hadoop/app/hive-1.1.0-cdh5.7.0/lib
[hadoop@hadoop001 lib]$ cp hive-common-1.1.0-cdh5.7.0.jar ~/app/sqoop-1.4.6-cdh5.7.0/lib/
[hadoop@hadoop001 lib]$ cp hive-shims-* ~/app/sqoop-1.4.6-cdh5.7.0/lib/
查看导入的数据:
[hadoop@hadoop001 sqoop-1.4.6-cdh5.7.0]$ hadoop fs -ls /user/hive/warehouse/
drwxr-xr-x - hadoop supergroup 0 2018-11-14 00:30 /user/hive/warehouse/emp_test
drwxr-xr-x - hadoop supergroup 0 2018-11-14 00:41 /user/hive/warehouse/emp_test_p
drwxr-xr-x - hadoop supergroup 0 2018-11-12 22:53 /user/hive/warehouse/xiaoyao.db
5.Hive==>MySQL
由于hive中的数据都是存在于HDFS上的,Hive==>MySQL的流程就是HDFS==> MySQL的流程。
导入流程:
创建emp_test表,结构于emp一致;
执行命令:[hadoop@hadoop001 ~]$ sqoop export --connect jdbc:mysql://localhost:3306/sqoop --username root --password 123456 --table emp_test --export-dir /user/hive/warehouse/xiaoyao.db/emp_test --input-fields-terminated-by '\t'
然后进入mysql数据库中查看数据。
6.简单运用
需求:统计每个区域下最受欢迎的产品TOPN
6.1准备数据
创建产品表:
create table product_info(
product_id int,
product_name string,
extend_info string
)
row format delimited fields terminated by '\t';
创建城市表:
create table city_info(
city_id int,
city_name string,
area string
)
row format delimited fields terminated by '\t';
创建用户行为的表:
create table user_click(
user_id int,
session_id string,
action_time string,
city_id int,
product_id int
) partitioned by(date string)
row format delimited fields terminated by ',';
如果数据量比较大情况下,请先将数据导入到mysql中,然后使用sqoop将数据导入到hive。
6.2需求分析
先获取产品编号和城市编号:
select product_id, city_id from user_click
where date='2016-05-05'
and product_id <> 0
将上面的求的结果和城市信息进行关联:
create table tmp_product_click_basic_info
as
select
u.product_id, u.city_id, c.city_name, c.area
from
(select product_id, city_id from user_click
where date='2016-05-05'
and product_id <> 0) u
join
(select city_id,city_name, area from city_info) c
on u.city_id = c.city_id;
各个区域各商品的点击次数:根据之前计算出来的数据,来进行分组
create table tmp_area_product_click_count as
select product_id,area,count(1) as click_count from tmp_product_click_basic_info group by product_id,area;
检索出产品名字
create table tmp_area_product_click_count_full_info as
select a.product_id,b.product_name,a.click_count, a.area from tmp_area_product_click_count a join product_info b on a.product_id=b.product_id;
求每个区域下最受欢迎的top3
create table area_product_click_count_top3
as
select *,
case when click_count >=10 and click_count<20 then 'lower'
when click_count>=20 and click_count<30 then 'middle'
else 'highest'
end click_count_grade,
'2016-05-05' day
from (
select
product_id,product_name,click_count,area,
row_number() over(partition by area order by click_count desc) rank
from tmp_area_product_click_count_full_info
) t where t.rank <=3 ;
row_number 参考自:https://blog.csdn.net/gumengkai/article/details/51356045,https://blog.csdn.net/hr541659660/article/details/75243787,https://www.cnblogs.com/ianunspace/p/5057333.html
get_json_object适用于数据量比较小的情况。