21HIVE的基本操作——好程序

 

表的修改操作

不建议用 in ,not in ,exists,not exists,而是用join
in
not in
exists
not exists
join

查看表
show create table 表名

修改表:直接rename表明
hive
alter table t_name rename to  (comment:说明)
alter table t3 rename to t_userinfo;

修改列名:alter table change column  改列名直接change 而且列名后面必须带上数据类型
alter table t4 change column name uname string;

修改列的位置   放在哪个字段的后面,或者直接放到第一个
改了结构,但是数据还是原样不动,所以实质的数据和元数据两边之间没有任何交互,它只是个文件,不会任何改变
alter table t4 change column uname uname string after age;

alter table t4 change column uname uname string first;

修改字段类型:string是不能转为int的
alter table t4 change column uname uname int;  ----2.x 

增加字段:add columns  字段名与字段类型
alter table t4 add columns(
sex int ,
addr string
)
;


不是用dorp,drop则是将数据给干掉
删除字段:replace columns  

alter table t4 replace columns(  --这里面写的是不删除的字段
id int,
name string,
addr string
)
;

7、内部表和外部表的转换:其实也就是修改表的属性
内部转外部
alter table t4 set tblproperties('EXTERNAL'='TRUE');   ##true必须大写
外部转内部
alter table t4 set tblproperties('EXTERNAL'='false');  ##false大小写都没关系


删除库:
drop database if exists gp1923;--但是它是要为非空的数据库才可以,否则报错
drop database if exists gp1923 cascade;##强制删除


hive的高级查询——sql的语句、执行顺序

查询基本语法
select distinct --having比这个执行顺序高  (distinct 排序性能很差 ,having的执行顺序高,查询的字段也是having的字段)
from  --从那张表
join on  --关联条件  
where --过滤
group by  --分组(分组的字段如果不再聚合函数内,则一定在这个后面)
having --后面带的是聚合函数,对聚合后的结果进行过滤
distribute by / cluster by  --分桶查询(和MapReduce的getPartitioner分区一样的操作,就是把查询分到多个Reduce里面)
order by / sort by --前一个是全局排序,就是一个reducetask,后一个是局部排序,就相当于maktask分区内进行排序
limit 
union / union all --聚合多个查询的结果,前一个排序去重,后一个不排序,不去重 


sql的执行顺序
from left_table   (结果集)
on id>5           (b结果集)
join              (笛卡尔积) 
where 
group by 
having
select
distinct
order by 
limit    
union /union all

注意点
尽量不要使用in 、not in、exists、not exists
查询尽量避免join操作,但是join是永远避免不了的
查询永远是小表驱动大表(小结果集驱动大结果集)
表的连接:
内连接 inner join
外连接 outer join
左外连接 left outer join
右外连接 right outer join
全外连接 full outer join

 

hive的特有的类型

left semi join:(代替exists、not exists)

join :
inner join :
from a,b:内连接、多表逗号,3者效果差不多,相互连接上才能出来结果

join不带任何的on或者where条件,就是笛卡尔积

left join/left outer join/left semi join :
数据以左表的数据为准,左表存在的数据都查询出,右表的数据关联上就出来,关联不上以NULL代替

left join 和left outer join 基本上是一样的
left semi join的结果集只包含左表的数据,一般用来判断数据是否存在。

right join /right outer join
以右表为准,右表的数据全都出来,左表没有关联上的数据以NULL替代
这两个得到的结果也是一样的。


full outer join (左右两表都出来)

hive提供小表标识:使用的是STREAMTABLE(小表别名)

select
/*+STREAMTABLE(d)*/
d.name,
e.name
from u1 e
join u2 d 
on d.id = e.id
;

 

map-side join:

如果所有的表中有小表,将会把小表缓存内存中,然后在map端进行连接关系查找。hive在map端
查找时将减小查询量,从内存中读取缓存小表数据,效率较快,还省去大量数据传输和shuffle耗时。

注意看该属性:

set hive.auto.convert.join=true   --设置了这个就默认为小表
select
e.*
from u1 d 
join u2 e
on d.id = e.id
;

以前的老版本,需要添加(/*+MAPJOIN(小表名)*/)来标识该join为map端的join。hive 0.7以后hive已
经废弃,但是仍然管用:????需要再测试看看是否有效???

select
/*+MAPJOIN(d)*/
e.*
from u1 d 
join u2 e
on d.id = e.id
;

到底小表多大才会被转换为map-side join:
set hive.mapjoin.smalltable.filesize=25000000   约23.8MB

 

hive练习

create table student(
sId int,
sName string,
sAge date,
sGender String
)row format delimited fields terminated by '\t'; --以Tab键分隔


create table course(
cId int,
cname string,
tId int
)row format delimited fields terminated by '\t';


create table teacher(
tId int,
tName String
)row format delimited fields terminated by '\t';

create table score(
sid int,
cid int,
score int
)row format delimited fields terminated by '\t';

创完表,然后到将数据加载到表里面

 

inner join和outer join 区别:

1、分区字段对outer join的on条件无效,对inner join的on有效的
有inner join但是没有full inner join
有full outer join但是没有outer join
所有join连接,只支持等值连接(= 和 and),不支持!= <> or 

on:所有on只支持等值连接 and

where:where后面通常是表达式,还可以是非聚合函数表达式(但是不能是聚合函数表达式)

group by:分组,通常和聚合函数搭配使用
查询的字段要么出现在group by 之后,要么出现在聚合函数之内

having:对分组后的集合结果进行过滤

sort by:局部排序,只保证单个的reduce中数据有序
order by:全局排序,保证所有reduce端的数据有序。

如果reduce只有一个,两者结果一样
两者通常跟asc desc搭配

只使用order by,reduce的个数只能是1个

设置reduce的数量:
set mapreduce.job.reduces=3;

limit :从结果集中取数据的条数

union:去重+排序
union all:不去重不排序


函数:

内置函数查看命令: show functions;  可以查看所有的内在函数
查看函数对应用法:desc function concat_ws; 可以查看得到给出的提示,是传字符串还是传二进制的值

 

窗口函数(考点)

排名函数
row_number:没有并列,相同名次顺序排
rank:有并列,相同名次有空位(有多少同名就空出多少个空位)
dense_rank:有并列,相同名次无空位

成绩表

create table if not exists stu_score(
dt string,
name string,
score int
)
row format delimited   --格式
fields terminated by '\t'--用tab分隔
;

1、对每次考试按照成绩的高低排序

select *
from stu_score
order by dt,score desc

 

over开窗子句

开窗里面写的就是分区的语句
不带聚合的结果
开窗


需求:
求每次考试的成绩top 3  (按照考试来分组,每组出三个,所以不是用limit)

 

先进行下面的查询

--排名要分每次的考试,,每次的考试分到Reduce里面,所以用到开窗函数,
--开窗的话则在每一行上面都会返回对应的结果  所有的聚合函数都可以进行开窗来做,但是不带聚合的结果,几条进则几条出
select 
*,
row_number() over(distribute by dt order by dt asc,score desc) rn,--写的就是分区的语句,按照谁进行分区。数据倒序排
rank() over(partition by dt order by score desc) rk,
dense_rank() over(partition by dt order by score desc) drk
from stu_score
;

 

在对下面的查询进行限制条件


select 
*
from 
(
select 
*,
row_number() over(distribute by dt sort by dt asc,score desc) rn, 
rank() over(distribute by dt sort by score desc) rk,
dense_rank() over(distribute by dt sort by score desc) drk
from stu_score
) a 
where a.rn < 4
;

1.x:partition by只和 order by 搭配使用
distribute by 只和sort by 搭配使用 
2.x:没有以上限制


2、需求:
求每次考试的最高分、最低分(单纯求最高最低才用聚合函数)

select dt,
max(score) as maxscore,
min(score) as minscore
from stu_score
group by dt
;

 

2、求每一次考试的的每一位同学与最高分的差值(先用聚合,再用开窗)

select sc.*,a.maxscore,a.minscore
from stu_score sc
join 
(select dt,
max(score) as maxscore,
min(score) as minscore
from stu_score
group by dt) a on a.dt = sc.dt 
;

---输出结果,不再是聚合的结果,分析开窗函数先将数据分区,然后在分区内进行聚合,然后将聚合的结果输出到每一条数据之中

窗口函数是先将数据进行分区,在分区内先计算聚合的值,计算完后,将计算结果追加到每一行的后面,然后都返回,这就是窗口函数的作用,它在分组了,分组是在over内部进行制定分组,按什么字段分组,差别是在输出结果,输出的不是聚合的结果,而是没有聚合的

--原来有多少条数据开窗后还是多少条数据,如果没有开窗,则就需要在select后面加上聚合函数 做一个group by,
--则所有的字段都要放进来
select 
*,
max(score) over(distribute by dt) maxscore,--分区后求最大的一个
min(score) over(distribute by dt) minscore--分区后求最小的一个
from stu_score
;

看上面两个结果,其实是一样的。

 

最大最小值也可以用first_value和last_value来求

将每次修改都把数据记录下来,找第一个版本,或者最后一个版本,所以按照时间排序
select 
*,
first_value(score) over(distribute by dt sort by score desc) maxscore,
last_value(score) over(distribute by dt sort by score desc) minscore
from stu_score
;

得出的结果可以看出,最小值是当前行的最小值,也就是默认的限制了比较方法

 

window子句:可以指定数据窗口的范围

后面接的都是范围

ROWS BETWEEN  界限
UNBOUNDED PRECEDING   第一行
UNBOUNDED FOLLOWING      最后一行
CURRENT ROW  --当前行

 

2 PRECEDING  当前和的前两行
2 FOLLOWING  当前行的后两行,通过这些指令来指定查询的范围

--last_value指定从第一行到最后一行
select 
*,
first_value(score) over(distribute by dt sort by score desc) maxscore,
last_value(score ignore nulls) over(distribute by dt sort by score desc ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) minscore
from stu_score
;

场景:
数据存在多版本的情况,获取第一个版本、最后一个版本的数据
要求的版本的数据是null,要排除null的版本数据,则在first_value和last_value中加上ignore nulls 忽略null值

 

需求:
求每一位学员的每次考试的成绩对比
dt name score upscore

select sc.*,upsc.score as upscore
from stu_score sc 
left join stu_score upsc on upsc.name = sc.name and upsc.dt = '2019-07-06'
where sc.dt = '2019-07-13' 
;

是因为得到结果集后再进行过滤

 

select sc.*,upsc.score as upscore
from stu_score sc 
left join stu_score upsc on upsc.name = sc.name 
where sc.dt = '2019-07-13' and upsc.dt = '2019-07-06'
;

 

lag和lead

lag(column_name,offset,default_value):往上取offset位置的数据
lead(column_name,offset,default_value):往下取offset位置的数据

--去上一次考试的成绩,偏移量是1。
--每一个学员的成绩对比,开窗则用学员名字进行分组,按照考试先后顺序排序
select 
*,
lag(score,1) over(distribute by name sort by dt asc) upscore
from stu_score
;

 

3个排名(分析函数)
first_value、 last_value、lag lead


&& || 
false && null =false
true || null =true


自定义函数(重点)

为什么要有自定义函数
hive的内置函数满足不了所有的业务需求
hive提供很多的模块可以自定义功能,比如:自定义函数、serde(序列化和反序列化)、输入输出格式

常用的自定义函数有哪些
udf:用户自定义函数,user defined function。一对一的输入输出。(最常用的)
udaf:用户自定义聚合函数,user defined aggregate function。多对一的输入输出
udtf:用户自定义表生成函数(查询结果返回的是一张表)。user defined table-generate function。一对多的输入输出。

 

1、编写UDF的方法

1、继承UDF,重写evaluate(),允许重载()(常用)
2、继承genericUDF,重写initlizer()、getdisplay()、evaluate()。

小写转大写

 

2、UDF的使用方法

一:(只在当前session有效)
1、将编写好的jar打包并上传到服务器上,并将jar包添加到hive的classpath中(因为依赖都在里面)

如何加入呢,则用下面的命令,加进来
hive>add jar /root/gp1923demo-1.0-SNAPSHOT.jar;

如果不想写上面这的可以用

<property>
    <name>hive.aux.jars.path</name>
    <value>$HIVE_HOME/auxlib</value>
    <description>The location of the plugin jars that contain implementations of user defined functions and serdes.</description>
  </property>

按照下面三个命令操作(使用hive、使用哪个库、将jar包拉取上来)

2、创建临时函数(创建永久的话要放到hdfs上)
create temporary function myUpCase as 'qfedu.com.bigdata.hiveUDF.firstUDF';

输入show functions;查看刚刚增加的方法

3、检查
第一个测试方法:也可以在本地测试
创建一个表dual,用于测试

create table if not exists dual(id string);
insert into dual values(' ');

第二个用java测试

temp
4、注销(删除临时函数的方法)
drop temporary function if exists myupcase;--要告诉是哪一个库


二:(只在当前session有效)
1、编译jar并上传
2、创建配置文件
vi ./hive-init,将下面的两句放入

add jar /root/gp1923demo-1.0-SNAPSHOT.jar;
create temporary function myUpCase as 'qfedu.com.bigdata.hiveUDF.firstUDF';

3、启动hive的时候带初始化文件
hive -i ./hive-init


三:
1、编译jar并上传
2、创建配置文件
在bin目录下创建一个配置文件,文件名.hiverc
vi bin/.hiverc

add jar /root/gp1923demo-1.0-SNAPSHOT.jar;
create temporary function myUpCase as 'qfedu.com.bigdata.hiveUDF.firstUDF';

3、重启hive   (这个不用字初始化文件)

 

四:
编译源码:(费劲)
1)将写好的Java文件拷贝到~/install/hive-0.8.1/src/ql/src/java/org/apache/hadoop/hive/ql/udf/ 
cd  ~/install/hive-0.8.1/src/ql/src/java/org/apache/hadoop/hive/ql/udf/
ls -lhgt |head
2)修改~/install/hive-0.8.1/src/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java,增加import和RegisterUDF

import com.meilishuo.hive.udf.UDFIp2Long;   //添加import

registerUDF("ip2long", UDFIp2Long.class, false); //添加register
3)在~/install/hive-0.8.1/src下运行ant -Dhadoop.version=1.0.1 package
cd ~/install/hive-0.8.1/src
ant -Dhadoop.version=1.0.1 package
4)替换exec的jar包,新生成的包在/hive-0.8.1/src/build/ql目录下,替换链接    
cp hive-exec-0.8.1.jar /hadoop/hive/lib/hive-exec-0.8.1.jar.0628
rm hive-exec-0.8.1.jar
ln -s hive-exec-0.8.1.jar.0628 hive-exec-0.8.1.jar
5)重启进行测试

 


案例1:生日转换成年龄


输入:string birthday 1990-06-21
输出:int age 29

 

案例2:根据key值找出value值

如:sex=1&hight=180&weight=130&sal=28000

json格式:
{sex:1,hight:180,weight:130,sal:28000}

 


案例3:正则表达式解析日志:

解析前:
220.181.108.151 - - [31/Jan/2012:00:02:32 +0800] \"GET /home.php?mod=space&uid=158&do=album&view=me&from=space HTTP/1.1\" 200 8784 \"-\" \"Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)\"

解析后:
220.181.108.151    20120131 120232    GET    /home.php?mod=space&uid=158&do=album&view=me&from=space    HTTP    200    Mozilla

 

案例4:Json数据解析UDF开发

有原始json数据如下:
{"movie":"1193","rate":"5","timeStamp":"978300760","uid":"1"}
{"movie":"661","rate":"3","timeStamp":"978302109","uid":"1"}
{"movie":"914","rate":"3","timeStamp":"978301968","uid":"1"}
{"movie":"3408","rate":"4","timeStamp":"978300275","uid":"1"}
{"movie":"2355","rate":"5","timeStamp":"978824291","uid":"1"}
{"movie":"1197","rate":"3","timeStamp":"978302268","uid":"1"}
{"movie":"1287","rate":"5","timeStamp":"978302039","uid":"1"}

最终我要得到一个结果表:
movie    rate    timestamp    uid
1197    3    978302268    1

步骤:
1、创建一个单字段的表关联原始的json数据
2、创建一个自定义的UDF,利用自定义函数将json数据解析成\t分割的字符串
3、将数据插入到临时表
4、使用split函数将解析后的数据切分成4个字段存入到最终结果表

设计四个字段,实现get,set方法

将json解析成类(对象)

 

1、先创建这个表,然后将json整进去

create table if not exists t_movie_rate(
json string
)
;

 

2、上传json文件,加载数据,查看一下

 

3、然后将jar包copy出来,

add jar /root/gp1923demo-1.0-SNAPSHOT.jar;
create temporary function parserJson as 'qfedu.com.bigdata.hiveUDF.JsonParser';

执行一下这个命令

然后可以查询

 

create table if not exists t_movie_tmp
as 
select parserjson(json) as json from t_movie_rate;


测试:(看看能不能截取)

select split(json,'\t')[0] as movie,split(json,'\t')[1] rate,split(json,'\t')[2] ts,split(json,'\t')[3] uid
from t_movie_tmp
limit 10
;

将数据按tab分隔

再创表,将查询的结果插入进去

create table t_movierate 
row format delimited 
fields terminated by '\t'
as
select split(json,'\t')[0] as movie,split(json,'\t')[1] rate,split(json,'\t')[2] ts,split(json,'\t')[3] uid
from t_movie_tmp
;
select * from t_movierate
limit 10;

 

get_json_object(第一种处理json串)

里面是有一个函数的,get_json_object可以处理一般的json的解析,传入json传,给定一个路径,路径就是key的值,就会将路径转为json的串
 

select get_json_object(json,'$.movie') as movie,get_json_object(json,'$.rate') as rate,get_json_object(json,'$.timeStamp') as ts,get_json_object(json,'$.uid') as uid
from t_movie_rate
limit 10
;

 

 

json_tuple(第二种处理json串)

p1,p2,pn,多个参数,返回一个元组,输入输出都是string

select movie,rate,ts,uid
from t_movie_rate lateral view json_tuple(json,'movie','rate','timeStamp','uid') js as movie,rate,ts,uid
limit 10
;

 

 

INSERT OVERWRITE TABLE u_data_new
SELECT
  TRANSFORM (movie ,rate, ts,uid)
  USING 'python weekday.py'
  AS (movieid, rating, weekday,userid)
FROM t_movierate;

 


练习:
Hive实战案例——级联求和accumulate
需求:
有如下访客访问次数统计表 t_access_times
访客    月份    访问次数
A    2015-01    5
A    2015-01    15
B    2015-01    5
A    2015-01    8
B    2015-01    25
A    2015-01    5
A    2015-02    4
A    2015-02    6
B    2015-02    10
B    2015-02    5
……    ……    ……

需要输出报表:t_access_times_accumulate
访客    月份    月访问总计    累计访问总计
A    2015-01    33    33
A    2015-02    10    43
A   2015-03 23    66
…….    …….    …….    …….
B    2015-01    30    30
B    2015-02    15    45
…….    …….    …….    …….

select uid,month,sum(mpv) over(distibute by uid sort by month asc ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS totalpv
from (
select uid,month,sum(pv) as mpv
from t
group by uid,month
)
;

 

hive的高级应用
hive的总结

r是rownumber   ,d是有并列,a是有并列

select id,unix_timestamp(uv_time) - unix_timestamp(lag(uv_time,1,uv_time) over(sort by uv_time asc)),unix_timestamp(lead(uv_time,1,uv_time) over(sort by uv_time) - unix_timestamp(uv_time)
from t
;

select aa.name ,bb.name 
from team aa
join team bb
where aa.name < bb.name (<>双循环)
;

 

select uid
from t
where unix_timstamp(ts) - unix_timestamp(lag(ts,100) over(distribute by uid sort by ts asc)) < 300
group by uid
;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值