Hive
数据类型
struct类型
- struct:结构体,对应了Java中的对象,实际上是将数据以
json
形式来进行存储和处理 - 案例
- 原始数据
a tom,19,male amy,18,female
b bob,18,male john,18,male
c lucy,19,female lily,19,female
d henry,18,male david,19,male
- 案例
-- 建表
create table groups (
group_id string,
mem_a struct<name:string, age:int, gender:string>,
mem_b struct<name:string, age:int, gender:string>
) row format delimited
fields terminated by ' '
collection items terminated by ',';
-- 加载数据
load data local inpath '/opt/hive_data/infos' into table groups;
-- 查询数据
select * from groups;
-- 获取成员a的信息
select mem_a from groups;
-- 获取成员a的名字
select mem_a.name from groups;
运算符和函数
概述
- 在Hive中,提供了非常丰富的运算符和函数,用于对数据进行处理和分析。在Hive中,运算符和函数可以归为一类
- 如果需要查看Hive中所有的函数,可以通过
show functions;
- 如果想要查看某一个函数的描述,可以使用
-- 简略描述
desc function sum;
-- 详细描述
desc function extended sum;
- 在Hive中,还允许用户自定义函数
- 在Hive中,函数必须结合其他的关键字来构成语句!
入门案例
- 案例一:给定字符串表示日期,例如’2024-03-25’,从获取年份
-- 方式一:以-拆分字符串,获取数组的第一位,将字符串转化为整数类型
select cast(split('2024-03-25', '-')[0] as int);
-- 方式二:正则表达式-捕获组
select cast(regexp_extract('2024-03-25', '(.*)-(.*)-(.*)', 1) as int);
-- 方式三:提供了year函数,直接用于提取年份,要求年月日之间必须用-隔开
select year('2024-03-25');
- 案例一:给定字符串表示日期,例如’2024/03/25’,从获取年份
-- 方式一
select cast(split('2024/03/25', '/')[0] as int);
-- 方式二
select cast(regexp_extract('2024/03/25', '(.*)/(.*)/(.*)', 1) as int);
-- 方式三:先将/替换为-,再利用year函数来提取
select year(regexp_replace('2024/03/25', '/', '-'));
常用函数
nvl函数
nvl(v1, v2)
:判断v1的值是否为null,如果v1的值不是null,那么返回v1,如果v1的值是null,那么返回v2- 案例
- 原始数据
1 Adair 800
2 David 600
3 Danny 1000
4 Ben 500
5 Grace
6 Cathy 700
7 Kite
8 Will 600
9 Thomas 800
10 Tony 1000
- 案例
-- 建表
create table rewards (
id int,
name string,
reward double
) row format delimited fields terminated by ' ';
-- 加载数据
load data local inpath '/opt/hive_data/rewards' into table rewards;
-- 查询数据
select * from rewards;
-- 计算每一个人平均发到的奖金是多少
-- avg属于聚合函数,所有的聚合函数在遇到null的时候自动跳过不计算
-- select avg(reward) from rewards;
select avg(if(reward is not null, reward, 0.0)) from rewards;
-- nvl
select avg(nvl(reward, 0)) from rewards;
case-when函数
- 类似于Java中的
switch-case
结构,是对不同的情况进行选择 - 案例
- 原始数据
1 bob 财务 男
2 bruce 技术 男
3 cindy 技术 女
4 david 财务 男
5 eden 财务 男
6 frank 财务 男
7 grace 技术 女
8 henry 技术 男
9 iran 技术 男
10 jane 财务 女
11 kathy 财务 女
12 lily 技术 女
- 案例
-- 建表
create table employers (
id int,
name string,
department string,
gender string
) row format delimited fields terminated by ' ';
-- 加载数据
load data local inpath '/opt/hive_data/employers' into table employers;
-- 查询数据
select *
from employers;
-- 需求:统计每一个部门的男生和女生人数
-- 方式一:sum(if())
select department as `部门`,
sum(if(gender = '男', 1, 0)) as `男`,
sum(if(gender = '女', 1, 0)) as `女`
from employers
group by department;
-- 方式:sum(case-when)
select department as `部门`,
sum(case gender when '男' then 1 else 0 end) as `男`,
sum(case gender when '女' then 1 else 0 end) as `女`
from employers
group by department;
explode函数
- explode在使用的时候,需要传入一个数组或者是映射类型的参数。如果传入的是数组,那么会将数组中的每一个元素拆分成单独的一行构成一列数据;如果传入的是映射,那么会将映射的键和值拆分成两列
- 案例:单词统计
-- 创建目录
dfs -mkdir /words
-- 将文件复制到这个目录下
dfs -cp /txt/words.txt /words
-- 查看数据
dfs -ls /words
-- 建表
-- 注意:数据在HDFS上已经存在,所以应该建立外部表
create external table words (
line array<string>
) row format delimited
collection items terminated by ' '
location '/words';
-- 查询数据
select * from words;
-- 需求:统计这个文件中每一个单词出现的次数
-- 思路
-- 第一步:先将数组中的元素转成一列
select explode(line)
from words;
-- 第二步:统计单词出现的次数
-- 基本结构:select x, count(x) from tableName group by x;
select w, count(w) from (
select explode(line) as w from words
) t1 group by w;
列转行
- 列转行,顾名思义,指的是将一列的数据拆分成多行数据。在列转行的过程中,最重要的函数就是
explode
- 案例
- 原始数据
沙丘2 剧情/动作/科幻/冒险
被我弄丢的你 剧情/爱情
堡垒 剧情/悬疑/历史
热辣滚烫 剧情/喜剧
新威龙杀阵 动作/惊悚
周处除三害 动作/犯罪
- 案例
-- 建表
create table movies (
name string, -- 电影名
kinds array<string> -- 电影类型
) row format delimited
fields terminated by ' '
collection items terminated by '/';
-- 加载数据
load data local inpath '/opt/hive_data/movies' into table movies;
-- 查询数据
select * from movies;
-- 需求:查询所有的动作片
-- lateral view function(ex) tableAlias as colAlias
-- 列转行,又称之为'炸列'
select name, k
from movies lateral view explode(kinds) ks as k
where k = '动作';
- 案例二
- 原始数据
bob 开朗,活泼 打游戏,打篮球
david 开朗,幽默 看电影,打游戏
lucy 大方,开朗 看电影,听音乐
jack 内向,大方 听音乐,打游戏
- 案例
-- 建表
create table persons (
name string, -- 姓名
characters array<string>, -- 性格
hobbies array<string> -- 爱好
) row format delimited
fields terminated by '\t'
collection items terminated by ',';
-- 加载数据
load data local inpath '/opt/hive_data/persons' into table persons;
-- 查询数据
select * from persons;
-- 获取性格开朗且喜欢打游戏的人
select name, c, h
from persons
lateral view explode(characters) cs as c
lateral view explode(hobbies) hs as h
where c = '开朗'
and h = '打游戏';
行转列
- 行转列,将多行的数据合并成一列
- 案例
select * from students_tmp;
-- 将同年级同班级的学生放到一起
-- collect_list和collect_set将数据合并到一个数组中
-- 不同的地方在于,collect_list允许有重复数据,但是collect_set不允许元素重复
-- concat_ws(符号,元素),表示将后边的元素之间用指定的符号进行拼接,拼接成一个字符串
select grade as `年级`,
class as `班级`,
concat_ws(', ', collect_list(name)) as `学生`
from students_tmp
group by grade, class;
分类
- 除了窗口函数以外,将其他的函数分为了3类:UDF、UDAF和UDTF函数
- UDF:User Defined Function,用户定义函数,特点是一进一出,即用户输入一行数据会获取到一行结果,例如
year
,split
,concat_ws
,regexp_replace
,regexp_extract
等 - UDAF:User Defined Aggregation Function,用户定义聚合函数,特点是多进一出,即用户输入多行数据会获取到一行结果,例如
sum
,avg
,count
,max
,min
,collect_list
,collect_set
等 - UDTF:User Defined Table-generated Function,用户定义表生成函数,特点是一进多出,即用户输入一行数据能够获取到多行结果,例如
explode
,inline
、stack
等 - 在Hive中,大部分函数都是UDF函数
自定义函数
- 自定义UDF:需要定义一个类,Hive1.x和Hive2.x继承
UDF
类,但是Hive3.x,UDF类已经过时,所以需要继承GenericUDF
- 自定义UDTF:需要定义一个类,继承
GenericUDTF
- 打成jar包,然后上传到HDFS上
- 在Hive中创建函数
-- 基本语法
create function 函数名
as '包名.类名'
using jar '在HDFS上的存储路径';
-- UDF
create function indexOf
as 'com.fesco.AuthUDF'
using jar 'hdfs://hadoop01:9000/F_Hive-1.0-SNAPSHOT.jar';
-- UDTF
create function splitLine
as 'com.fesco.AuthUDTF'
using jar 'hdfs://hadoop01:9000/F_Hive-1.0-SNAPSHOT.jar';
-- 测试
select indexOf('welcome', 'm');
select splitLine('welcome to big data', ' ');
- 删除函数
drop function indexOf;
窗口函数
概述
- 窗口函数又称之为开窗函数,用于限定要处理的数据范围
- 基本语法结构
分析函数 over(partition by 字段 order by 字段 [desc/asc] rows between 起始范围 and 结束范围)
partition by
对数据进行分类order by
对数据进行排序rows between x and y
指定数据的处理范围
关键字 | 解释 |
preceding | 向前 |
following | 向后 |
unbounded | 无边界 |
current row | 当前行 |
- 示例:假设当前处理的第5行数据
-
2 preceding and current row
:处理前两行到当前行。即处理第3~5行的数据 -
current row and 3 following
:处理当前行以及向后3行。即处理第5~8行的数据 -
unbounded preceding and current row
:从第一行到当前行 -
current row and unbounded following
:从当前行到最后一行
- 分析函数:大致可以分为三组
- 聚合函数,例如
sum
,avg
等 - 移位函数,包含
lag
,lead
,ntil
- 排序函数,包含
row_number
,rank
,dense_rank
案例
- 原始数据
jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94
- 建表
-- 建表
create table orders
(
name string,
order_date string,
cost int
) row format delimited fields terminated by ',';
-- 加载数据
load data local inpath '/opt/hive_data/orders' into table orders;
- 需求一:查询每一位顾客的消费明细以及到消费日期为止的总消费金额
-- 思路:
-- 1. 拆寻每一位顾客的信息,那么需要按照顾客姓名来分类
-- 2. 按照日期,将订单进行排序
-- 3. 计算总消费金额,所以需要求和
-- 4. 到当前消费日期为止的金额,也就意味着是获取从第一行到当前行的数据来处理
select *,
sum(cost) over (partition by name order by order_date rows between unbounded preceding and current row ) as total_cost
from orders;
补充:正则捕获组
概述
- 在正则表达式中,将
()
括起来的部分,称之为捕获组,此时可以将捕获组看作是一个整体 - 在正则表达式中,默认会对捕获组进行编号,编号是从1开始的。编号的计算,是从捕获组左半边括号出现的顺序来依次计算的
例如:(AB(C(D)E)F(G))
1 AB(C(D)E)F(G)
2 C(D)E
3 D
4 G
- 在正则表达式中,可以通过
\n
的形式来引用对应编号的捕获组。例如\1
表示引用编号为1的捕获组