hive查询 排序和聚集 通过hive提供的order by子句可以让最终的输出结果整体有序。但是因为hive是基于hadoop之上的,要生成这种整体有序的结果,就必须强迫hadoop只利用一个reduce来完成处理。这种方式的副作用就是回降低效率。 如果你不需要最终结果整体有序
hive查询排序和聚集通过hive提供的order by子句可以让最终的输出结果整体有序。但是因为hive是基于hadoop之上的,要生成这种整体有序的结果,就必须强迫hadoop只利用一个reduce来完成处理。这种方式的副作用就是回降低效率。
如果你不需要最终结果整体有序,你就可以使用sort by子句来进行排序。这种排序操作只保证每个reduce的输出是有序的。如果你希望某些特定行被同一个reduce处理,则你可以使用distribute子句来完成。比如:
表student(classno,stuno,score)数据如下:
c01 n0101 82
c01 n0102 59
c02 n0201 81
c01 n0103 65
c03 n0302 92
c02 n0202 82
c02 n0203 79
c03 n0301 56
c03 n0306 72
我们希望按照成绩由低到高输出每个班级的成绩信息。执行以下语句:
select classno,stuno,score from student distribute byclassno sort by score;
输出结果为:
c02 n0203 79
c02 n0201 81
c02 n0202 82
c03 n0301 56
c03 n0306 72
c03 n0302 92
c01 n0102 59
c01 n0103 65
c01 n0101 82
我们可以看到每一个班级里所有的学生成绩是有序的。因为同一个classno的记录会被分发到一个单独的reduce处理,而同时sort by保证了每一个reduce的输出是有序的。
注意:
为了测试上例中的distribute by的效果,你应该首先设置足够多的reduce。比如上例中有3个不同的classno,则我们需要设置reduce个数至少为3或更多。如果设置的reduce个数少于3,将会导致多个不同的classno被分发到同一个reduce,从而不能产生你所期望的输出。设置命令如下:
set mapred.reduce.tasks = 3;
mapreduce脚本如果我们需要在查询语句中调用外部脚本,比如python,则我们可以使用transform,map,reduce等子句。
比如,我们希望过滤掉所有不及格的学生记录,只输出及格学生的成绩信息。
新建一个python脚本文件score_pass.py,内容如下:
#! /usr/bin/env python
import sys
for line in sys.stdin:
(classno,stuno,score)= line.strip().split('\t')
ifint(score) >= 60:
print%s\t%s\t%s %(classno,stuno,score)
执行以下语句
add file /home/user/score_pass.py;
select transform(classno,stuno,score) using'score_pass.py' as classno,stuno,score from student;
输出结果为:
c01 n0101 82
c02 n0201 81
c01 n0103 65
c03 n0302 92
c02 n0202 82
c02 n0203 79
c03 n0306 72
注意:
1) 以上python脚本中,分隔符只能是制表符(\t)。同样输出的分隔符也必须为制表符。这个是有hive自身决定的,不能更改,不要尝试使用其他分隔符,否则会报错。同时需要调用strip函数,以去除掉行尾的换行符。(或者直接使用不带参数的line.split()代替。
2) 使用脚本前,先使用add file语句注册脚本文件,以便hive将其分发到hadoop集群。
3) transfom传递数据到python脚本,as语句指定输出的列。
连接(join)直接编程使用hadoop的mapreduce是一件比较费时的事情。hive则大大简化了这个操作。
内连接(inner join)和sql的内连相似。执行以下语句查询每个学生的编号和教师名:
select a.stuno,b.teachername from student a join teacherb on a.classno = b.classno;
输出结果如下:
n0203 sun
n0202 sun
n0201 sun
n0306 wang
n0301 wang
n0302 wang
n0103 zhang
n0102 zhang
n0101 zhang
注意:
数据文件内容请参照上一篇文章。
不要使用select xx from aa bb where aa.f=bb.f这样的语法,hive不支持这种写法。
如果需要查看hive的执行计划,你可以在语句前加上explain,比如:
explain select a.stuno,b.teachername from student a jointeacher b on a.classno = b.classno;
外连接(outer join)和传统sql类似,hive提供了left outer join,right outer join,full out join。
半连接(semi join)hive不提供in子查询。此时你可以用leftsemi join实现同样的功能。
执行以下语句:
select * from teacher left semi join student onstudent.classno = teacher.classno;
输出结果如下:
c02 sun
c03 wang
c01 zhang
可以看出,c04 dong没有出现在查询结果中,因为c04在表student中不存在。
注意:
右表(student)中的字段只能出现在on子句中,不能出现在其他地方,比如不能出现在select子句中。
map连接(map join)当一个表非常小,足以直接装载到内存中去时,可以使用map连接以提高效率,比如:
select /*+mapjoin(teacher) */ a.stuno,b.teachernamefrom student a join teacher b on a.classno = b.classno;
以上红色标记部分采用了c的注释风格。
当连接时用到不等值判断时,也比较适合map连接。具体原因需要深入了解hive和mapreduce的工作原理。
子查询(sub query)运行以下语句将返回所有班级平均分的最高记录。
select max(avgscore) as mascore
from
(select classno,avg(score) as avgscore from student group byclassno) a;
输出结果:
80.66666666666667
以上语句中红色部分为一个子查询,且别名为a。返回的子查询结果和一个表类似,可以被继续查询。
视图(view)和传统数据库中的视图类似,hive的视图只是一个定义,视图数据并不会存储到文件系统中。同样,视图是只读的。
运行以下两个命令:
create view avg_score as
select classno,avg(score) as avgscore from student groupby classno;
select max(avgscore) as mascore
from avg_score;
可以看到输出结果和上例中的结果是一样的。