Hive(10) Hvie函数详解-常见函数使用和自定义函数


Hvie函数详解-常见函数使用和自定义函数

函数

常用系统内置的函数

nvl (空字段赋值)

有时候我们查到的一些值是NULL, 但是有时候NULL不能准确的表达含义和参与运算(NULL与任何值运算都为NULL), 比如说工资的奖金

这时我们可以使用nvl()函数, 在查询时将NULL值转换为一个默认值

nvl(<可能为空的字段>, <自定义默认值>);

举例 查询员工的工资和奖金, 如果为NULL, 则显示0

select 工资, nvl(奖金, 0)
from 员工表;

这时, 如果某个人的奖金为NULL, 就会显示为0而不是NULL


case when (判断)

有点类似于MySQL中的if() 函数

case <字段名> when <如果等于这个值> then <显示的值> else <如果不等于显示的值> end

举例 在员工表中, 统计每个部门男女各有多少人

select
	部门名称,
	sum(case 性别 when '男' then 1 else 0 end),
	sum(case 性别 when '女' then 1 else 0 end)from 员工表
group by 部门名称;

说明

这里巧妙的运用了case when, 用男性举例, 如果是男性, 就显示1, 然后再把1 作为sun() 的参数, 就实现了累加的效果


collect_set (行转为集合)

它的主要作用是将某字段的值进行去重汇总,产生一个array类型字段, 一般用于分组的时候

collect(<字段名>)

注意

函数只接受基本数据类型, 不接受集合类型

举例 加入一张表里有学生姓名(string)班级(string) 这两个字段, 要求查询每个班级的名称和这个班里的所有同学的姓名

select 班级, collect_set(学生姓名姓名) as 姓名
from 学生表 
group by 班级;

结果举例, 结果会是以下形式:

班级 姓名
1 [“小明”,“小刚”]
2 [“红红”, “莉莉”, “冬梅”]

explode (集合转为行)

与上面相反, Hive还可以将一个集合类型拆分成多行

explode() 是一个UDTF函数, 即user-defined table generating functions, 说白了就是一个可以生成一个新表的函数

explode(<要拆分的字段名>)

举例 假设有下面一张学生爱好表

姓名 爱好
小明 唱, 跳, rap
小刚 篮球
select explode(爱好) as 爱好
from 学生爱好;

结果:

爱好
rap
篮球

注意

虽然可以将集合(列)转换为行, 但是只是使用expode()函数,的话, 也只能查询分割的这一列的内容, 从上面这张表来说, 只能查询爱好 这一字段如果想下面这样查询, 就会出错:

select explode(爱好) as 爱好, 姓名
from 学生爱好;

因为UDTF函数不能和普通字段一起查询, 这时我们就需要一个可以与原表绑定的方法, 也就是lateral view

lateral view

表面含义是"侧视图", 是一种视图, 他的作用就是可以将UDTF分割后生成的新表, 和原来的行相关联, 从而可以是普通字段和UDTF字段一起查询, 其实就是将UDTF生成的表看做一个视图, 然后与原表的行相关联

使用lateral view 需要指定生成的视图名称

select <视图名>.*
from <原表名> 
lateral view <UDTF函数> <视图名>

举例 跟上面那个例子一样, 拆分爱好字段

select 爱好视图.*
from 学生爱好表 
lateral view explode(爱好) 爱好视图;

结果跟上面是一样的, 因为只是将explode()生成的表看做一个视图, 所以这样单独使用lateral view 并没有什么意义

我们是想要将该视图和原表的其他字段一起查询, 需要将该视图看做一个列, 还要指定这个列别名

select <列表名>, <原表中的字段>
from <原表名> 
lateral view  <视图名> as <列别名>

举例 根据上面的例子, 将每个爱笑对应的学生显示出来

select 爱好, 姓名
from 学生爱好表
lateral view explode(爱好) 爱好视图 as 爱好

这样就出现我们想要的结果了:

爱好 姓名
小明
小明
rap 小明
篮球 小刚

开窗函数

开窗函数有点类似于group by 分组函数, 但是分组查询时, 每个组只能返回一个聚合值, 如果说我们想要返回多个值的时候, 就没法使用分组查询完成了, 比如, 在电商网站中, 我想要查询每个每个顾客上一次购买物品的时间, 或者在流量分析中, 查询每个用户本周每天使用流量的累积

开窗函数一般分为两种:

  1. 聚合开窗函数
  2. 排序开窗函数

开窗函数在查询结果中其实就相当于一列, 该列使用over()修饰:

select <字段名称 | 聚合函数> over(<窗口范围条件>) [as <别名>]
from ...

说明

窗口范围条件:

参数 含义
默认(不填) 整个查询结果
partition by <字段名> 根据分区开窗, 每个分区一个窗口
order by <字段名> 跟在partition by <字段名> 后面, 给当前窗口排序
distribute by <字段名> sort by <字段名> 分区排序(在多个Reducer的情况下, 对每个Reducer结果内部排序)
rows 指定当前窗口包括那一行

rows属性

属性 含义
CURRENT ROW 当前行
n PRECEDING 往前n行
n FOLLOWING 往后n行数据
UNBOUNDED PRECEDING 表示从前面的起点
UNBOUNDED FOLLOWING 表示到后面的终点
LAG(col,n,default_val) 往前第n行数据, 如果数据为null, 就显示第三个参数
LEAD(col,n, default_val) 往后第n行数据, 如果数据为null, 就显示第三个参数
NTILE(n)
开窗函数举例

下面我们模拟一个名为购物表 电商网站的表(这里方便查看使用中文作为字段名, 但是在实际中不要使用中文):

类型 含义
姓名 string 姓名
购买日期 string 该用户购买物品的日期
消费 double 该用户本次购买物品的花费

举例 1 查询2020年1月购买过的顾客以及该月份购买的总人数

select 姓名, count(*) over()
from 购物表
where substring(购买日期, 1, 7) = '2020-01'
group by 姓名;

举例 2 将每个顾客的消费值, 按照日期累加显示

select 姓名, sum(消费) over(partition by 姓名 order by 购买日期)
from 购物表 ;

举例 3 同例2, 这里查询的是每个顾客本次加上上一次的消费总额

其实这里就是给每行结果开一个窗口, 窗口中是 当前消费额+上一次的消费额

select 
	姓名, 
	购买日期, 
	sum(消费) over(partition by 姓名 order by 购买日期 rows between 1 preceding and current row)
 from business ;

举例 4 查询每个顾客购买的信息详情和上一次购买的时间

其实这里就是给每行结果开一个窗口, 窗口中是 上一次的购物时间, 这里添加了一个默认值(“第一次购买”), 如果没有上一次, 说明是第一次购买, 即上一次为空, 这时就会显示"第一次购买"

select 
	姓名, 
	购买日期, 
	lag(购买日期, 1, "第一次购买") over(partition by 姓名 order by 购买日期)
from 购物表 ;

获取当前排序序号

通过开窗函数可以查看当前行的序号(排名), 开窗函数中有特定的函数用户获取序号, 总共有3中排序方式:

  • rank()

排序相同时会重复,总数不会变

  • dense_rank()

排序相同时会重复,总数会减少

  • row_number()

会根据顺序计算

**举例 ** 这种排序在成绩单上很常见, 假设有一张成绩表, 对比几种排名

姓名(string) 成绩(double)
小明 95
小刚 95
小红 80
小王 75
老王 75
select 
	姓名, 
	成绩, 
	rank() over(order by 成绩) as rank排名,
	dense_rank() over(order by 成绩) as dense_rank排名,
	row_number() over(order by 成绩) as row_number排名
from 成绩表;

结果:

姓名 成绩 rank排名 dense_rank排名 row_number排名
小明 95 1 1 1
小刚 95 1 1 2
小红 80 3 2 3
小王 75 4 3 4
老王 75 4 3 5



自定义函数

有时候Hive自带的函数不能满足我们的需求, 这时我们就需要自定义函数

自定义函数步骤

  1. 创建Maven工程, 引入Hive依赖
  2. 自定义一个类, 继承UDF(org.apache.hadoop.hive.ql.exec.UDF)
  3. 自定义一个名为evaluate() 的方法, 然后再里面实现自定义的函数体
  4. 上传jar包到/lib/ 目录下
  5. 重启hive客户端或者使用命令关联jar包
add jar "jar包路径";
  1. 从hive客户端创建一个临时函数关联自定义的函数
create temporary function testUpper as "<包路径.类名>";

自定义函数举例

举例 自定义一个函数, 要求实现字符串全部转换为大写

  1. 创建工程, 引入依赖

<dependency>
    <groupId>org.apache.hivegroupId>
    <artifactId>hive-execartifactId>
    <version>1.2.2version>
dependency>
  1. 自定义函数, 继承UDF父类, 自定义evaluate()函数, 注意, 这里的evaluate()不是UDF父类自带的函数, 需要自己命名成evaluate
package udf;

import org.apache.hadoop.hive.ql.exec.UDF;

/**
 * Description: 注意, 这里的报名最好是全英文路径,
 */
public class Upper extends UDF {
    public String evaluate(String str) {
        //判断是否为空, 如果为空, 则返回null
        if (str == null) {
            return null;
        }
        //不为空, 返回大写结果
        return str.toUpperCase();
    }
}

  1. 打成jar包

Hive(10) Hvie函数详解-常见函数使用和自定义函数_第1张图片

  1. 生成的jar包名字太复杂, 可以将jar包重命名一下, 然后上传到服务器/lib/ 目录下
  2. 然后重启客户端, 或者使用命令从hive客户端导入jar包, 这里的名字
add jar /opt/software/hive/lib/testUpper.jar;
  1. 创建一个临时函数, 关联自定义的函数
create temporary function testUpper as "udf.Upper";
  1. 测试
select testUpper(stu_name)
from stu_info ;

你可能感兴趣的:(大数据,#,Hive)