Hive高频函数(二)

前言

hive中有很大部分的函数是基于复杂类型去计算的,因为我们现实中的数据往往不是f(x)->y这种类型的,更多其实是f(x1,x2,x3)->y的类型。在这种场景下,hive提供了复杂类型的操作。数据的结构类型会决定udf作用的目标也不一样,这种场景下的udf往往会通过多步组合来得到我们想要的结果。

hive中的复杂类型盘点

类型说明
ARRAY包含同类型元素的数组,索引从0开始 ARRAY
MAP字典 MAP<primitive_type, data_type>
STRUCT结构体 STRUCT<col_name : data_type [COMMENT col_comment], …>
UNIONTYP联合体 UNIONTYPE<data_type, data_type, …>

这些数据类型同样提供了udf来生成,我们可以在源码中找到这部分:

    system.registerGenericUDF("array", GenericUDFArray.class);
    system.registerGenericUDF("assert_true", GenericUDFAssertTrue.class);
    system.registerGenericUDF("map", GenericUDFMap.class);
    system.registerGenericUDF("struct", GenericUDFStruct.class);
    system.registerGenericUDF("named_struct", GenericUDFNamedStruct.class);
    system.registerGenericUDF("create_union", GenericUDFUnion.class);
    system.registerGenericUDF("extract_union", GenericUDFExtractUnion.class);

常用UDF盘点

有了之前的准备,我们可以开始我们的udf解释了:
集合处理类函数

array

这个函数就是生成我们一个数组类型的结果:

select array('facebook', 'com','a') as url;
["facebook","com","a"]

需要注意显示的时候其实是会带有[]的字样

sort_array

这个函数其实是对我们的数组类似的结果进行排序,所以这个函数需要传入数组

select sort_array(array('facebook', 'com','a')) as url;
["a","com","facebook"]

用数字会更加明显一些:

select sort_array(array(1,3,6,5,8,9)) as url;
[1,3,5,6,8,9]

map

map对应的数据格式就是(k,v)的结构,我们用这个函数去构造map类型的数据对象:

select map("1","宋江","2","林冲")
{"1":"宋江","2":"林冲"}

聚合类函数

聚合函数需要作用在一个group的数据组中,对group by之后的结果进行处理,为了说明问题,我需要准备点数据,
表的结构情况:

desc temp.test_tab;
num                     int                                         
a                       string                                      
g1                      string 

表数据如下:

select * from temp.test_tab;
1       A       g
2       B       g
3       C       g
4       C       g
4       NULL    g

group_concat

函数说明:group_concat(col1, isUnique) - Aggregation function, collect all non-null col1 value into an array, if isUnique is non-zero, remove the duplicated values.
采集所有非空的列上面的值到一个数组中,isUnique如果非0,则会去掉重复的值。
我们先参数传0

select g1,group_concat(a,0) from temp.test_tab group by g1

g       ["A","B","C","C"]

再来一波非0的

select g1,group_concat(a,1) from temp.test_tab group  by g1;

g       ["A","B","C"]

collect_list

函数说明:Returns a list of objects with duplicates
这个函数其实就是返回数据聚合之后的数组对象,这里特别强调了一下会带重复

select g1,collect_list(a) from temp.test_tab group  by g1
g       ["A","B","C","C"]

collect_set

函数说明:Returns a set of objects with duplicate elements eliminated
这个函数和上面的函数想呼应,只不过结果会去重

select g1,collect_set(a) from temp.test_tab group  by g1;
g       ["A","B","C"]

需要说明的是,这样子返回去重的数据是不保证顺序的,实际情况我们需要顺序的时候会配合sort_array函数一起使用:

select g1,sort_array(collect_set(num)) from temp.test_tab group  by g1
g       [1,2,3,4]

concat_ws

这个函数在之前也有聊过,事实上,这个函数传入的类型可以是数组和简单类型的组合,放在这里说的原因是这个函数往往和上面的聚合函数进行组合

select concat_ws('.', 'www', array('facebook', 'com'))  as url;
www.facebook.com

因为可以传入数组,所以我们实际使用的时候会用把这个函数套上去,得到我们要的结果:

select g1,concat_ws(',',collect_list(a)) from temp.test_tab group  by g1
g       A,B,C,C

这次的变化在于,返回的结果已经是一个字符串类型了

转置类操作

explode

这个函数就是把横着的扳直,作用在map结构和list结构上

select explode(array(1,3,6,5,8,9)) as id 

id
1
3
6
5
8
9

map类型输出的列名就是key和value

select explode(map("1","宋江","2","林冲"))
key		value	
1       宋江
2       林冲

lateral view

这个其实是一个操作,因为基于explode操作之后,我们的表数据会被硬生生一行变成多行了,这个和原有的数据需要有一个对应的关系
比如我们之前的sql:

select g1,sort_array(collect_set(num)) as id from temp.test_tab group  by g1

这个生成的结果就是:

g	[1,2,3,4]

但是我们如果进行explode:

 select g1,explode(sort_array(collect_set(num))) as id from temp.test_tab group  by g1

这个操作其实就是类似两张表去做join操作了,类似这样:

g	[1,2,3,4]  => 要变成
g  1
g  2 
g  3 
g  4

这种情况的话在sql运算中其实没有做子查询的时候是不能实现的,这个时候就做了一个破坏了数据操作范式的语法lateral,把explode运算的结果,和原有的数据做一次类似join的操作,我们可以看下源码上对这一操作的描述:

The lateral view join operator is used for FROM src LATERAL VIEW udtf()...
 * This operator was implemented with the following operator DAG in mind.
 * 
 *            [Table Scan]
 *                |
 *       [Lateral View Forward]
 *              /   \
 *   [Select](*)    [Select](adid_list)
 *            |      |
 *            |     [UDTF] (explode)
 *            \     /
 *      [Lateral View Join]
 *               |
 *               |
 *      [Select] (pageid, adid.*)
 *               |
 *              ....

later view 在实际操作中是做了一次later view join的操作,结果集就会达到join的效果,举例说明:

select num,id from temp.test_tab lateral  view explode(array(1,3))q  as  id;

注意id的列名的来自后面生成的as id列,我们看图中的结果数据,每一个num值都和新的1 3关联上了,这个其实数据量也翻了两倍了

在这里插入图片描述
这个函数除了在把数据拉直的时候处理之外,还有个场景是把join两边数据不均匀的时候提前做分组,这样子可以避免数据倾斜。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值