前文

Hive的本质是MapReduce,MapReduce中如何排序的??

MapReduce分为几种:
1.全排序order By: 结果只有一个(也就是只有一个分区),所有的数据整体有序.
2.部分排 序sort By: 结果有多个(相当于有多个分区),每个分区内部有序的.
3.二次排序: 在排序时,比较的条件有多个,比如说按总流量排序,总流量相等就按上行流量排序.

注意:
排序是在reduce之前就已经排好序了,排序是shuffle阶段的主要工作.然后让Reduce方便接下来的处理

准备数据

准备 emp.txt到/root/soft 目录下面,

  1. 7369 SMITH CLERK 7902 1980-12-17 800.00 20
  2. 7499 ALLEN SALESMAN 7698 1981-2-20 1600.00 300.00 30
  3. 7521 WARD SALESMAN 7698 1981-2-22 1250.00 500.00 30
  4. 7566 JONES MANAGER 7839 1981-4-2 2975.00 20
  5. 7654 MARTIN SALESMAN 7698 1981-9-28 1250.00 1400.00 30
  6. 7698 BLAKE MANAGER 7839 1981-5-1 2850.00 30
  7. 7782 CLARK MANAGER 7839 1981-6-9 2450.00 10
  8. 7788 SCOTT ANALYST 7566 1987-4-19 3000.00 20
  9. 7839 KING PRESIDENT 1981-11-17 5000.00 10
  10. 7844 TURNER SALESMAN 7698 1981-9-8 1500.00 0.00 30
  11. 7876 ADAMS CLERK 7788 1987-5-23 1100.00 20
  12. 7900 JAMES CLERK 7698 1981-12-3 950.00 30
  13. 7902 FORD ANALYST 7566 1981-12-3 3000.00 20
  14. 7934 MILLER CLERK 7782 1982-1-23 1300.00 10

创建表

注意, 分隔符不要写错了,不然导入数据会导入不进来.

sql:

  1. create external table if not exists emp
  2. (
  3. empno int,
  4. ename string,
  5. job string,
  6. mgr int,
  7. hiredate string,
  8. sal double,
  9. comm double,
  10. deptno int
  11. ) row format delimited fields terminated by '\t';
  12. select *
  13. from emp;

导入数据

如果导入数据失败,看看是不是分隔符弄错了,,我曾经就出现过这个错误,弄了20分钟找不到问题,最后发现创建表的语句 \t 我给写成了 /t … = =. 结果就出现导入失败的情况.
sql:

  1. load data local inpath '/root/soft/emp.txt'
  2. into table emp;

查看导入的结果

sql

  1. select *
  2. from emp;

Order By全排序

Order By:全局排序,一个ReducerTask,也就是对所有的数据进行排序.如果多个Reduce的话是无用的.

使用 ORDER BY 子句排序

ASC(ascend): 升序(默认)
DESC(descend): 降序

案例
使用上和MySQL的order by没啥区别

  1. -- 查询员工信息按工资升序排列
  2. hive (default)> select * from emp order by sal;
  3. -- 查询员工信息按工资降序排列
  4. hive (default)> select * from emp order by sal desc;

Sort By 每个MapReduce内部排序

使用Sort By 的话, 需要将ReduceTask最少要大于1,不然没效果. 一个ReduceTask就是一个分区,五个ReduceTask就是五个分区.

每个Reducer内部进行排序,对全局结果集来说不是排序。

操作说明
设置Reduce个数
sql:

  1. -- 1.设置reduce个数
  2. set mapreduce.job.reduces=3;
  3. -- 2.查看设置reduce个数
  4. set mapreduce.job.reduces;
  5. --3.根据部门编号降序查看员工信息
  6. select *
  7. from emp sort by empno desc;

这样执行完了你会发现数据都是乱的,没有什么效果..

hive四种排序Order By , Sort By ,Distribute By ,Cluster By - 图1

需要将数据导出到文件里面才能看到效果
sql

  1. -- 将查询的语句导入到指定文件里面
  2. insert overwrite local directory '/root/soft/sortby-result'
  3. row format delimited fields terminated by '\t'
  4. select *
  5. from emp sort by sal desc;

此时Linux的/root/soft下会生成一个sortby-result文件夹
为什么是三个???
因为启动了三个ReduceTask 任务

  1. [root@zjj101 soft]# cd sortby-result/
  2. [root@zjj101 sortby-result]# ls
  3. 000000_0 000001_0 000002_0
  4. [root@zjj101 sortby-result]# pwd
  5. /root/soft/sortby-result
  6. [root@zjj101 sortby-result]#

依次查看这三个文件里面的内容

根据sal 降序排序,sal字段是从左往右数第六个字段, 你就能看到每个ReduceTask(分区)内部都是有序排列的了.

shell

  1. [root@zjj101 sortby-result]# ls
  2. 000000_0 000001_0 000002_0
  3. [root@zjj101 sortby-result]# cat 000000_0
  4. 7839 KING PRESIDENT \N 1981-11-17 5000.0 \N 10
  5. 7788 SCOTT ANALYST 7566 1987-4-19 3000.0 \N 20
  6. 7698 BLAKE MANAGER 7839 1981-5-1 2850.0 \N 30
  7. 7782 CLARK MANAGER 7839 1981-6-9 2450.0 \N 10
  8. 7844 TURNER SALESMAN 7698 1981-9-8 1500.0 0.0 30
  9. 7654 MARTIN SALESMAN 7698 1981-9-28 1250.0 1400.0 30
  10. [root@zjj101 sortby-result]# cat 000001_0
  11. 7566 JONES MANAGER 7839 1981-4-2 2975.0 \N 20
  12. 7499 ALLEN SALESMAN 7698 1981-2-20 1600.0 300.0 30
  13. 7934 MILLER CLERK 7782 1982-1-23 1300.0 \N 10
  14. 7521 WARD SALESMAN 7698 1981-2-22 1250.0 500.0 30
  15. 7876 ADAMS CLERK 7788 1987-5-23 1100.0 \N 20
  16. 7900 JAMES CLERK 7698 1981-12-3 950.0 \N 30
  17. [root@zjj101 sortby-result]# cat 000002_0
  18. 7902 FORD ANALYST 7566 1981-12-3 3000.0 \N 20
  19. 7369 SMITH CLERK 7902 1980-12-17 800.0 \N 20
  20. [root@zjj101 sortby-result]#

Distribute By 分区排序

分区和排序都是在shuffle阶段完成,分区是在MapTask阶段的Shuffle完成, 排序是在MapTask完成,在ReduceTask也有完成.
分区是使用partition分区器来进行分区的,当你的ReduceTask的个数大于1的时候,先设置用户自己定义的分区器,如果没有的话,缺省使用hash分区器,hash分区器特点是只用key的hashCode来分区.

你在输入查询语句执行查询的时候,底层是经过了MapReduce程序,会给你输入的字段都封装成key和value,分区只是对key来分区.那么你不知道你哪些数据分散到哪个ReduceTask里面.

如果你只写sort by的话,那么就是随机分区.如果你希望自己定义使用哪个字段来分区,那么你就需要使用Distribute By字段,这个Distribute By是指定你按哪个字段分区的. Distribute By在全排序是没有意义的,因为全排序是只有一个ReduceTask,那么不管你key是什么的话,全都是0号分区,所以说Distribute By只有结合部分排序才有意义的.所以一般情况下Distribute By 是结合sort by 来使用的

注意,Hive要求DISTRIBUTE BY语句要写在SORT BY语句之前。

对于distribute by进行测试,一定要分配多reduce进行处理,否则无法看到distribute by的效果。

案例

先按照部门编号分区,再按照员工编号降序排序。

sql:

  1. set mapreduce.job.reduces=3;
  2. insert overwrite local directory '/root/soft/sortby-result'
  3. row format delimited fields terminated by '\t'
  4. select *
  5. from emp distribute by deptno
  6. sort by empno desc;

注意: overwrite 这个是自动删除指定的目录.

执行完了之后会生成三个文件,因为是三个ReduceTask

仔细观察,部门号是最右面的那个,是按照部门号排序的,默认是hash分区器,然后每个ReduceTask内部是按照员工编号排序的,员工编号是最左面的一个字段.

  1. [root@zjj101 soft]# cd sortby-result/
  2. [root@zjj101 sortby-result]# ls
  3. 000000_0 000001_0 000002_0
  4. [root@zjj101 sortby-result]# cat 000000_0
  5. 7900 JAMES CLERK 7698 1981-12-3 950.0 \N 30
  6. 7844 TURNER SALESMAN 7698 1981-9-8 1500.0 0.0 30
  7. 7698 BLAKE MANAGER 7839 1981-5-1 2850.0 \N 30
  8. 7654 MARTIN SALESMAN 7698 1981-9-28 1250.0 1400.0 30
  9. 7521 WARD SALESMAN 7698 1981-2-22 1250.0 500.0 30
  10. 7499 ALLEN SALESMAN 7698 1981-2-20 1600.0 300.0 30
  11. [root@zjj101 sortby-result]# cat 000001_0
  12. 7934 MILLER CLERK 7782 1982-1-23 1300.0 \N 10
  13. 7839 KING PRESIDENT \N 1981-11-17 5000.0 \N 10
  14. 7782 CLARK MANAGER 7839 1981-6-9 2450.0 \N 10
  15. [root@zjj101 sortby-result]# cat 000002_0
  16. 7902 FORD ANALYST 7566 1981-12-3 3000.0 \N 20
  17. 7876 ADAMS CLERK 7788 1987-5-23 1100.0 \N 20
  18. 7788 SCOTT ANALYST 7566 1987-4-19 3000.0 \N 20
  19. 7566 JONES MANAGER 7839 1981-4-2 2975.0 \N 20
  20. 7369 SMITH CLERK 7902 1980-12-17 800.0 \N 20
  21. [root@zjj101 sortby-result]#

Cluster By

当distribute by和sorts by字段相同时,可以使用cluster by方式说白了就是如果你分区的字段和排序的字段一致的话,可以简写为Cluster By

cluster by就是distribute by+sort by的组合,但是只能默认升序。
cluster by除了具有distribute by的功能外还兼具sort by的功能。但是排序只能是升序排序,不能指定排序规则为ASC或者DESC。

以下两种写法等价,我就不演示了..

  1. select * from emp cluster by deptno;
  2. select * from emp distribute by deptno sort by deptno;