一、了解HIVE
1、是什么
- 是一个可以将sql翻译为MR程序的工具
- 支持用户将HDFS上的文件映射为表结构,用户可以输入SQL进行查询分析
- 将用户定义的库、表结构等信息存储在hive的元数据库中
2、用途
构建大数据体系下的数据仓库
3、使用方式
1)方式一:交互式查询
将hive启动为一个服务: bin/hiveserver ,然后可以在任意一台机器上使用beeline客户端连接hive服务,进行交互式查询
2)方式二:将hive作为命令一次性运行
事先将sql语句写入一个文件比如 q.hql ,然后用hive命令执行:bin/hive -f q.hql
3)方式三:将方式二写入一个xxx.sh脚本中
二、HIVE语句
1、三种执行模式
[root@node01 ~]# hive -e "use default;create table test_1(id int,name string);"
OK
Time taken: 2.453 seconds
OK
Time taken: 1.37 seconds
[root@node01 ~]# hive -e "desc test_1;"
OK
id int
name string
Time taken: 2.939 seconds, Fetched: 2 row(s)
[root@node01 home]# vi a.hql
1,xiaoming,20
2,xiaowang,22
[root@node01 home]# vi /home/userinfo.txt
use default;
create table test_2(id int,name string,age int)
row format delimited
fields terminated by ',';
load data local inpath '/home/userinfo.txt' into table test_2;
select count(*) from test_2;
[root@node01 home]# hive -f a.hql #运行
[root@node01 home]# hive -e "select * from test_2;"
OK
1 xiaoming 20
2 xiaowang 22
NULL NULL NULL
Time taken: 3.608 seconds, Fetched: 3 row(s)
[root@node01 home]# cd /usr/local/src/hive-1.2.1/bin/
[root@node01 bin]# ./hiveserver2
#光标定位到下一行不动
[root@node02 bin]# ./beeline
Beeline version 1.2.1 by Apache Hive
beeline> !connect jdbc:hive2://node01:10000
Connecting to jdbc:hive2://node01:10000
Enter username for jdbc:hive2://node01:10000: root
Enter password for jdbc:hive2://node01:10000:
Connected to: Apache Hive (version 1.2.1)
Driver: Hive JDBC (version 1.2.1)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://node01:10000> #连接到node01服务端
0: jdbc:hive2://node01:10000>
#可以查询node01中的内容(以表格形式)
0: jdbc:hive2://node01:10000> show databases;
+----------------+--+
| database_name |
+----------------+--+
| default |
+----------------+--+
1 row selected (3.375 seconds)
0: jdbc:hive2://node01:10000> show tables;
+-----------+--+
| tab_name |
+-----------+--+
| test_1 |
| test_2 |
+-----------+--+
2 rows selected (0.198 seconds)
0: jdbc:hive2://node01:10000> select * from test_2;
+------------+--------------+-------------+--+
| test_2.id | test_2.name | test_2.age |
+------------+--------------+-------------+--+
| 1 | xiaoming | 20 |
| 2 | xiaowang | 22 |
| NULL | NULL | NULL |
+------------+--------------+-------------+--+
3 rows selected (1.925 seconds)
#node02中每进行一条,node01中都会打印一个OK(因为命令都发到node01上的服务端执行)
[root@node01 bin]# ./hiveserver2
OK
OK
OK
2、建表
1)表定义信息会被记录到hive的元数据中(mysql的hive库)
在hdfs上的hive库目录中创建一个跟表名一致的文件夹
表中没有数据
#查询test_1中的字段信息
[root@node01 home]# hive -e "desc test_1;"
id int
name string
sge int
Time taken: 2.572 seconds, Fetched: 3 row(s)
#有字段id和name,age,我们创建一个文件,好后上传到hdfs对应的test_1表对应的目录下
[root@node01 home]# vi test_1.txt
1,zhangsan,12
2,lisi,32
[root@node01 home]# hadoop fs -put test_1.txt /user/hive/warehouse/test_1
表中有数据
改进
#以上结果
hive> select * from test_1;
OK
NULL NULL NULL
NULL NULL NULL
#建表时没有指定分隔符
#删除表
hive> drop table test_1;
#重新创建一个带有分隔符的表
hive> create table test_1(id string,name string,age int)
> row format delimited
> fields terminated by ',';
#重新上传文件
[root@node01 home]# hadoop fs -put test_1.txt /user/hive/warehouse/test_1
#查看结果
hive> select * from test_1;
OK
1 zhangsan 12
2 lisi 32
#再创建一个文件
[root@node01 home]# vi test_1.txt.1
3,xiaoming,14
4
5,lili3
[root@node01 home]# hadoop fs -put test_1.txt.1 /user/hive/warehouse/test_1
#不填默认为null
hive> select * from test_1;
OK
1 zhangsan 12
2 lisi 32
3 xiaoming 14
4 NULL NULL
5 lili3 NULL
NULL NULL
3、内部表和外部表
1)内部表
#创建表
hive> create table t_2(id int,name string,salary bigint,add string)
> row format delimited
> fields terminated by ','
> location '/aa/bb';
[root@node01 home]# vi /home/salary.txt
1,apple,4,weifang
2,banana,2,hainan
3,orange,4,hunan
4,liulian,100,mangu
#运行
hive> load data local inpath '/home/salary.txt' into table t_2;
hive> select * from t_2;
OK
1 apple 4 weifang
2 banana 2 hainan
3 orange 4 hunan
4 liulian 100 mangu
#删除表
hive> drop table t_2;
hdfs中的文件也会被删除
2)外部表(external)
hive> create external table t_3(id int,name string,salary bigint,add string)
> row format delimited
> fields terminated by ','
> location'/aa/bb';
[root@node01 home]# hadoop fs -put salary.txt /aa/bb/
[root@node01 home]# hadoop fs -cat /aa/bb/salary.txt
1,apple,4,weifang
2,banana,2,hainan
3,orange,4,hunan
4,liulian,100,mangu
hive> select * from t_3;
OK
1 apple 4 weifang
2 banana 2 hainan
3 orange 4 hunan
4 liulian 100 mangu
#删除表
hive> drop table t_3;
数据目录不会删除
3)小结
- 说明: location '/aa/bb’是hdfs的目录
- 区别: 内部表的目录由hive创建在默认的仓库目录下:/user/hive/warehouse/…(也可以指定)
外部表的目录由用户建表时自己指定: location ‘/位置/’
drop一个内部表时,表的元信息和表数据目录都会被删除;
drop一个外部表时,只删除表的元信息,表的数据目录不会删除; - 意义: 通常,一个数据仓库系统,数据总有一个源头,而源头一般是别的应用系统产生的,其目录无定法,为了方便映射,就可以在hive中用外部表进行映射;并且,就算在hive中把这个表给drop掉,也不会删除数据目录,也就不会影响到别的应用系统。
4、 分区关键字 PARTITIONED BY
#创建
hive> create table test_44(ip string,url string,staylong int)
> partitioned by(day string)
> row format delimited
> fields terminated by ',';
[root@node01 home]# vi pv.data.2019-05-10
192.168.9.10,www.a.com,1000
192.168.10.10,www.b.com,100
192.168.11.10,www.c.com,900
192.168.12.10,www.d.com,100
192.168.13.10,www.e.com,2000
hive> load data local inpath '/home/pv.data.2019-05-10' into table test_44 partition(day='2019-05-10');
[root@node01 home]# vi pv.data.2019-05-11
192.168.9.11,www.f.com,100
192.168.10.12,www.g.com,10
192.168.11.13,www.h.com,90
192.168.12.14,www.i.com,10
192.168.13.15,www.g.com,200
hive> load data local inpath '/home/pv.data.2019-05-11' into table test_44 partition(day='2019-05-11');
#查询
hive> select * from test_44;
OK
192.168.9.10 www.a.com 1000 2019-05-10
192.168.10.10 www.b.com 100 2019-05-10
192.168.11.10 www.c.com 900 2019-05-10
192.168.12.10 www.d.com 100 2019-05-10
192.168.13.10 www.e.com 2000 2019-05-10
192.168.9.11 www.f.com 100 2019-05-11
192.168.10.12 www.g.com 10 2019-05-11
192.168.11.13 www.h.com 90 2019-05-11
192.168.12.14 www.i.com 10 2019-05-11
192.168.13.15 www.g.com 200 2019-05-11
Time taken: 0.745 seconds, Fetched: 10 row(s)
#分区查询
hive> select * from test_44 where day='2019-05-11';
OK
192.168.9.11 www.f.com 100 2019-05-11
192.168.10.12 www.g.com 10 2019-05-11
192.168.11.13 www.h.com 90 2019-05-11
192.168.12.14 www.i.com 10 2019-05-11
192.168.13.15 www.g.com 200 2019-05-11
Time taken: 2.097 seconds, Fetched: 5 row(s)
#查询某天访问人数
hive> select distinct ip from test_44 where day='2019-05-11';
5、导入、导出数据
1)导入数据
#将hive运行所在机器的本地磁盘上的文件导入表中
hive> load data local inpath '/home/pv.data.2019-05-11' overwrite into table test_4 partition(day=”2019-05-12”);
#覆盖test_4表的day=”2019-05-12”分区 的数据
#将hdfs中的文件导入表中
hive> load data inpath '/user.data.2' into table t_1;
#不加local关键字,则是从hdfs的路径中移动文件到表目录中;
#从别的表查询数据后插入到一张新建表中
hive> create table t_1_iz
> as
> select id,name from test_1;
hive> select * from t_1_iz;
OK
1 zhangsan
2 lisi
3 xiaoming
4 NULL
5 lili3
NULL
#从别的表查询数据后插入到一张已存在的表中
#新建一个字段一样的表
hive> create table t_1_hd like test_1;
#从test_1中查询一些数据出来插入到t_1_hd中:
hive> insert into table t_1_hd
> select
> id,name,age
> from test_1
> where name='zhangsan';
#结果
hive> select * from t_1_hd;
OK
1 zhangsan 12
[root@node01 home]# vi test_1.txt.2
[root@node01 home]# hadoop fs -put test_1.txt.2 /user/hive/warehouse/test_1
6,lxx,45
7,xxl,36
8,lss,13
hive> insert into table t_1_hd
> select
> id,name,age
> from test_1
> where name like'%l';
hive> select * from t_1_hd;
OK
1 zhangsan 12
7 xxl 36
hive> insert overwrite table t_1_hd
> select
> id,name,age
> from test_1
> where name like'l%';
hive> select * from t_1_hd;
OK
2 lisi 32
5 lili3 NULL
6 lxx 45
8 lss 13
#关于分区数据导入另外一张表
#建表
hive> create table t_4_hd like test_4;
#导入
hive> insert into table t_4_hd partition(day='2019-04-10')select ip,url,staylong from test_44 where day='2019-05-10';
#查看
hive> select * from t_4_hd;
OK
192.168.9.10 www.a.com 1000 2019-04-10
192.168.10.10 www.b.com 100 2019-04-10
192.168.11.10 www.c.com 900 2019-04-10
192.168.12.10 www.d.com 100 2019-04-10
192.168.13.10 www.e.com 2000 2019-04-10
2)导出数据
#将数据从hive的表中导出到hdfs的目录中
#没有此目录将会自动生成
hive> insert overwrite directory '/aa/test_1'
> select * from test_1 where name='xxl';
hive> insert overwrite local directory '/aa/test_1_2'
> row format delimited
> fields terminated by ','
> select * from test_1 limit 100;
#输出为表格形式
[root@node01 test_1_2]# hive -e "select * from test_1" | tr "\t" "," > result.csv
[root@node01 test_1_2]# ll
总用量 8
-rw-r--r-- 1 root root 98 8月 29 02:19 000000_0
-rw-r--r-- 1 root root 112 8月 29 02:26 result.csv
#将数据从hive的表中导出到本地磁盘目录中
hive> insert overwrite local directory'/aa/bb'
> select * from test_1;
[root@node01 test_1_2]# cd /aa/bb/
[root@node01 bb]# ll
总用量 4
-rw-r--r-- 1 root root 98 8月 29 04:11 000000_0
[root@node01 bb]# cat 000000_0
1zhangsan12
2lisi32
3xiaoming14
4\N\N
5lili3\N
\N\N
6lxx45
7xxl36
8lss13
\N\N
6、HIVE的存储文件格式
HIVE支持很多种文件格式: SEQUENCE FILE | TEXT FILE | PARQUET FILE | RC FILE
#创建一张t_seq,指定文件格式sequencefile
hive> create table t_seq(id int,name string)
> stored as sequencefile;
#往表t_seq中插入数据
hive> insert into table t_seq
> select * from test_1;
#hive会生成sequence文件插入表目录中
7、表的分区
#查看表的分区
hive> show partitions test_44;
OK
day=2019-05-10
day=2019-05-11
#添加分区
hive> alter table test_44 add partition(day='2019-05-12')partition(day='2017-04-13');
hive> show partitions test_44;
OK
day=2017-04-13
day=2019-05-10
day=2019-05-11
day=2019-05-12
#向新增分区中导入数据
#load
hive> load data local inpath '/aa/pv.data.2019-05-12' into table test_44 partition(day='2019-05-12');
hive> select * from test_44 where day='2019-05-12';
OK
192.168.9.11 www.f.com 100 2019-05-12
192.168.10.12 www.g.com 12 2019-05-12
192.168.11.13 www.h.com 12 2019-05-12
192.168.12.14 www.i.com 12 2019-05-12
#insert
hive> insert into table test_44 partition(day='2019-05-13')
> select ip,url,staylong from test_44 where day='2019-05-11' and staylong>20;
hive> select * from test_44 where day='2019-05-13';
OK
192.168.9.11 www.f.com 100 2019-05-13
192.168.11.13 www.h.com 90 2019-05-13
192.168.13.15 www.g.com 200 2019-05-13
#删除分区
hive> alter table test_44 drop partition(day='2019-05-13');
hive> select * from test_44;
OK
192.168.9.10 www.a.com 1000 2019-05-10
192.168.10.10 www.b.com 100 2019-05-10
192.168.11.10 www.c.com 900 2019-05-10
192.168.12.10 www.d.com 100 2019-05-10
192.168.13.10 www.e.com 2000 2019-05-10
192.168.9.11 www.f.com 100 2019-05-11
192.168.10.12 www.g.com 10 2019-05-11
192.168.11.13 www.h.com 90 2019-05-11
192.168.12.14 www.i.com 10 2019-05-11
192.168.13.15 www.g.com 200 2019-05-11
192.168.9.11 www.f.com 100 2019-05-12
192.168.10.12 www.g.com 12 2019-05-12
192.168.11.13 www.h.com 12 2019-05-12
192.168.12.14 www.i.com 12 2019-05-12
8、表的列定义
#查看表的定义
hive> desc t_seq;
OK
id string
name string
age int
#添加列
hive> alter table t_seq add columns(address string);
hive> desc t_seq;
OK
id string
name string
age int
address string
#全部替换
hive> alter table t_seq replace columns(id int,name string,addredd string,age int);
hive> desc t_seq;
OK
id int
name string
addredd string
age int
#修改已存在的列定义
hive> alter table t_seq change id uid string;
hive> desc t_seq;
OK
uid string
name string
addredd string
age int
9、显示命令
#显示所有库
hive> show databases;
#显示所有表
hive> show tables;
#显示表的分区
hive> show partitions test_4;
#显示hive中所有的内置函数
hive> show functions
#显示表定义
hive> desc test_4;
#显示表定义的详细信息
hive> desc extended test_4;
#显示表定义的详细信息,并且用比较规范的格式显示
hive> desc formatted test_4;
#清空表数据,保留表结构
hive> truncate table test_4_st_200;
hive> desc test_44;
OK
ip string
url string
staylong int
day string
#Partition Information
#col_name data_type comment
day string
Time taken: 0.177 seconds, Fetched: 9 row(s)
hive> select * from test_44;
OK
Time taken: 0.225 seconds
#设置本地运行hive的mapreduce,不提交给yarn
hive>set hive.exec.mode.local.auto=true;
10、insert(插入)
1)加载数据到表中
load、insert(请到前面寻找)
2)插入数据
#插入单条数据
hive> insert into table t_seq values('9','haha','beijing','28');
#多重插入
#从test_44中筛选出不同的数据,插入另外两张表中;
hive> create table test_4_st_200 like test_44;
#添加分区只能是day
hive> alter table test_4_st_200 add partition(day='lt200');
#将staylong小于200的数据添加到test_4_st_200,day='lt200'分区中
hive> insert into table test_4_st_200 partition(day='lt200')
>select ip,url,staylong from test_44 where staylong<200;
hive> select * from test_4_st_200;
OK
192.168.10.10 www.b.com 100 lt200
192.168.12.10 www.d.com 100 lt200
192.168.9.11 www.f.com 100 lt200
192.168.10.12 www.g.com 10 lt200
192.168.11.13 www.h.com 90 lt200
192.168.12.14 www.i.com 10 lt200
#将staylong大于200的数据添加到test_4_st_200,day='gt200'分区中
hive> insert into table test_4_st_200 partition(day='gt200')
>select ip,url,staylong from test_44 where staylong>200;
hive> select * from test_4_st_200;
OK
192.168.9.10 www.a.com 1000 gt200
192.168.11.10 www.c.com 900 gt200
192.168.13.10 www.e.com 2000 gt200
192.168.10.10 www.b.com 100 lt200
192.168.12.10 www.d.com 100 lt200
192.168.9.11 www.f.com 100 lt200
192.168.10.12 www.g.com 10 lt200
192.168.11.13 www.h.com 90 lt200
192.168.12.14 www.i.com 10 lt200
**但是以上实现方式有一个弊端,两次筛选job,要分别启动两次mr过程,要对同一份源表数据进行两次读取
如果使用多重插入语法,则可以避免上述弊端,提高效率:源表只要读取一次即可**
hive> from test_44
>insert into table test_4_st_200 partition(day='lt200')
>select ip,url,staylong where staylong<200
>insert into table test_4_st_200 partition(day='gt200')
>select ip,url,staylong where staylong>200;
hive> select * from test_4_st_200;
OK
192.168.9.10 www.a.com 1000 gt200
192.168.11.10 www.c.com 900 gt200
192.168.13.10 www.e.com 2000 gt200
192.168.9.10 www.a.com 1000 gt200
192.168.11.10 www.c.com 900 gt200
192.168.13.10 www.e.com 2000 gt200
192.168.10.10 www.b.com 100 lt200
192.168.12.10 www.d.com 100 lt200
192.168.9.11 www.f.com 100 lt200
192.168.10.12 www.g.com 10 lt200
192.168.11.13 www.h.com 90 lt200
192.168.12.14 www.i.com 10 lt200
192.168.10.10 www.b.com 100 lt200
192.168.12.10 www.d.com 100 lt200
192.168.9.11 www.f.com 100 lt200
192.168.10.12 www.g.com 10 lt200
192.168.11.13 www.h.com 90 lt200
192.168.12.14 www.i.com 10 lt200
11、分桶表
参考:https://www.cnblogs.com/kouryoushine/p/7809299.html
1)定义
将数据按照指定的字段进行分成多个桶中去,就是将数据按照字段进行划分,可以将数据按照字段划分到多个文件当中去
2)使用
#开启桶表功能
hive> set hive.enforce.bucketing=true;
#设置reduce个数
hive> set mapreduce.job.reduces=3;
#创建桶表
hive> create table course(c_id string,c_name string,t_id string)clustered by(c_id)into 3 buckets row format delimited fields terminated by '\t';
桶表的数据加载: 由于通过hdfs dfs -put文件或者通过load data均不好使,所以只能通过insert overwrite
创建普通表,并通过insert overwrite的方式将普通表的数据通过查询的方式加载到桶表当中去
#创建普通表:
hive> create table course_common (c_id string,c_name string,t_id string) row format delimited fields terminated by '\t';
#普通表中加载数据
hive> load data local inpath '/home/course.csv' into table course_common;
hive> insert overwrite course select * from course_common;
12、GROUP BY语句
#创建分区表语法
hive> create table score(s_id string,c_id string, s_score int) partitioned by (month string) row format delimited fields terminated by '\t';
#加载数据到分区表中
hive> load data local inpath '/home/score.csv' into table score partition (month='201909');
GROUP BY语句通常会和聚合函数一起使用,按照一个或者多个列队结果进行分组,然后对每个组执行聚合操作。
案例实操:
#计算每个学生的平均分数
hive> select s_id ,avg(s_score) from score group by s_id;
#注意group by的字段,必须是select后面的字段,select后面的字段不能比group by的字段多
#计算每个学生最高成绩
hive> select s_id ,max(s_score) from score group by s_id;
13、HAVING语句
1)having与where不同点
- where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据。
- where后面不能写分组函数,而having后面可以使用分组函数。
- having只用于group by分组统计语句。
2)案例实操:
#求每个学生的平均分数
hive> select s_id ,avg(s_score) from score group by s_id;
#求每个学生平均分数大于85的人
hive> select s_id ,avg(s_score) avgscore from score group by s_id having avgscore > 85;
14、JOIN语句
等值JOIN
老版本中,不支持非等值的join
在新版中:1.2.0后,都支持非等值join
1)案例
①查询分数对应的姓名
#创建学生表老师表:
hive> create table student (s_id string,s_name string,s_birth string , s_sex string ) row format delimited fields terminated by '\t';
hive> create table teacher (t_id string,t_name string) row format delimited fields terminated by '\t';
#加载数据
hive> load data local inpath '/home/teacher.csv' into table teacher;
hive> load data local inpath '/home/student.csv' into table student;
SELECT s.s_id,s.s_score,stu.s_name,stu.s_birth FROM score s LEFT JOIN student stu ON s.s_id = stu.s_id;
好处:
- 使用别名可以简化查询。
- 使用表名前缀可以提高执行效率。
②实例
合并老师与课程表
select * from teacher t join course c on t.t_id = c.t_id;
#内连接(INNER JOIN):只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
hive> select * from teacher t inner join course c on t.t_id = c.t_id;
#左外连接(LEFT OUTER JOIN):JOIN操作符左边表中符合WHERE子句的所有记录将会被返回。
#查询老师对应的课程
hive> select * from teacher t left join course c on t.t_id = c.t_id;
#右外连接(RIGHT OUTER JOIN):JOIN操作符右边表中符合WHERE子句的所有记录将会被返回。
hive> select * from teacher t right join course c on t.t_id = c.t_id;
#满外连接(FULL OUTER JOIN):将会返回所有表中符合WHERE语句条件的所有记录。如果任一表的指定字段没有符合条件的值的话,那么就使用NULL值替代。
hive> SELECT * FROM teacher t FULL JOIN course c ON t.t_id = c.t_id ;
#多表连接
#注意:连接 n个表,至少需要n-1个连接条件。例如:连接三个表,至少需要两个连接条件。
#多表连接查询,查询老师对应的课程,以及对应的分数,对应的学生
#设置表头
hive> set hive.cli.print.header=true;
>select * from teacher t
>left join course c
>on t.t_id = c.t_id
>left join score s
>on s.c_id = c.c_id
>left join student stu
>on s.s_id = stu.s_id;
大多数情况下,Hive会对每对JOIN连接对象启动一个MapReduce任务。本例中会首先启动一个MapReduce job对表teacher和表course进行连接操作,然后会再启动一个MapReduce job将第一个MapReduce job的输出和表score;进行连接操作。
排序
15、排序
1)全局排序
Order By:全局排序,一个reduce
- 使用 ORDER BY 子句排序
ASC(ascend): 升序(默认)
DESC(descend): 降序 - ORDER BY 子句在SELECT语句的结尾
案例实操
#查询学生的成绩,并按照分数降序排列
SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score DESC;
#查询学生的成绩,并按照分数升序排列
SELECT * FROM student s LEFT JOIN score sco ON s.s_id = sco.s_id ORDER BY sco.s_score asc;
#按照别名排序
#按照分数的平均值排序
select s_id ,avg(s_score) avg from score group by s_id order by avg;
#多个列排序
#按照学生id和平均成绩进行排序
select s_id ,avg(s_score) avg from score group by s_id order by s_id,avg;
每个MapReduce内部排序(Sort By)局部排序
#Sort By:每个MapReduce内部进行排序,对全局结果集来说不是排序。
#设置reduce个数
set mapreduce.job.reduces=3;
#查看设置reduce个数
set mapreduce.job.reduces;
#查询成绩按照成绩降序排列
select * from score sort by s_score;
#将查询结果导入到文件中(按照成绩降序排列)
insert overwrite local directory '/export/servers/hivedatas/sort' select * from score sort by s_score;
2)分区排序(DISTRIBUTE BY)
Distribute By: 类似MR中partition,进行分区,结合sort by使用。
注意:
- Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。
- 对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。
案例实操:
先按照学生id进行分区,再按照学生成绩进行排序。
#设置reduce的个数,将我们对应的s_id划分到对应的reduce当中去
hive> set mapreduce.job.reduces=7;
#通过distribute by 进行数据的分区
hive> insert overwrite local directory '/home/sort' select * from score distribute by s_id sort by s_score;
16、CLUSTER BY
当distribute by和sort by字段相同时,可以使用cluster by方式。
cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是倒序排序,不能指定排序规则为ASC或者DESC。
#以下两种写法等价
hive> select * from score cluster by s_id;
hive> select * from score distribute by s_id sort by s_id;
三、关于成绩分区的MapReduce实例
course
score
student
teacher
package com.doit.scorep;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;
public class ScorePartitioner extends Partitioner<Text,Text> {
// @Override
// public int getPartition(Text score, Text id, int i) {
//
// int scoreInt = Integer.parseInt(score.toString());
// if(scoreInt>=90 && scoreInt <100) return 0;
// if (scoreInt<90 && scoreInt>=80) return 1;
// if (scoreInt<80) return 2;
//
// }
@Override
public int getPartition(Text score, Text text2, int i) {
int scoreInt = Integer.parseInt(score.toString());
int a = 3;
if (scoreInt>=90 && scoreInt <100) {a=0;}
if (scoreInt<90 && scoreInt>=80) {a=1;}
if (scoreInt<80) {a=2;}
return a;
}
}
package com.doit.scorep;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class Score {
// 1 70
// 2 74
// 3 65
// 4 80
// 5 98
// 6 94
// 7 99
// 8 75
public static class ScoreMap extends Mapper<LongWritable, Text,Text,Text>{
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] split = value.toString().split(" ");
String id = split[0];
String score = split[1];
context.write(new Text(score), new Text(id));
}
}
public static class ScoreReducer extends Reducer<Text,Text,Text,IntWritable>{
TreeMap<Integer, Text> treeMap;
@Override
protected void setup(Context context) throws IOException, InterruptedException {
treeMap = new TreeMap<Integer, Text>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.println("-------------------se******&&&&&tup----------");
}
@Override
protected void reduce(Text score, Iterable<Text> id, Context context) throws IOException, InterruptedException {
// treeMap.put(Integer.parseInt(score.toString()), id.iterator().next());
Text ids = id.iterator().next();
String scores = score.toString();
treeMap.put(Integer.parseInt(scores),ids);
}
@Override
protected void cleanup(Context context) throws IOException, InterruptedException {
Iterator<Map.Entry<Integer, Text>> iterator = treeMap.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<Integer, Text> entry = iterator.next();
Integer score = entry.getKey();
Text id = entry.getValue();
context.write(id,new IntWritable(score));
}
System.out.println("------------------clea******&&&&&&&nup---------");
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(Score.class);
job.setNumReduceTasks(3);
job.setPartitionerClass(ScorePartitioner.class);
job.setMapperClass(ScoreMap.class);
job.setReducerClass(ScoreReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.setInputPaths(job, new Path("E:\\mrtest\\scores\\input"));
Path outPath = new Path("E:\\mrtest\\scores\\output");
FileSystem fileSystem = FileSystem.get(conf);
if(fileSystem.exists(outPath)){
fileSystem.delete(outPath, true);
}
FileOutputFormat.setOutputPath(job, outPath);
boolean b = job.waitForCompletion(true);
System.exit(b?0:1);
}
}