Hive零基础从入门到实战 进阶篇(十二) HiveQL:表生成函数(行转列)

目录

 

前言

1. 表生成函数表

2. 函数功能演示

2.1 explode(ARRAY)

2.2 explode(MAP)

2.3 posexplode(ARRAY)

2.4 stack(INT n, v_1, v_2, ..., v_k)

2.5 json_tuple(jsonStr, k1, k2, ...)

2.6 parse_url_tuple(url, p1, p2, ...)

3. 表生成函数必备:lateral view

3.1 lateral view语法

3.2 应用1:行转列

3.3 应用2:求总聚合结果


 

 

前言

在Hive中,所有的表生成函数,包括用户自定义的和内置的,都统称为用户自定义表生成函数(user defined table generating functions),简称UDTF。本文只介绍Hive自带的内置表生成函数。

 

1. 表生成函数表

返回数值类型 函数名\所需参数\参数数据类型 描述

N rows

explode(ARRAY)

返回n行,每行对应数组中的一个元素

N rows

explode(MAP)

返回n行两列,每行对应每个map键-值,第一列是map的键,第二列是map的值

N rows

posexplode(ARRAY)

与explode类似,不同的是除了数组元素本身,还返回各元素在数组中的位置

N rows

stack(INT n, v_1, v_2, ..., v_k)

把k列转换成n行,k/n列,其中n必须是个常数

tuple

json_tuple(jsonStr, k1, k2, ...)

从一个JSON字符串中获取多个key对应的value并作为一个元组返回,与get_json_object不同的是此函数能一次获取多个键值

tuple

parse_url_tuple(url, p1, p2, ...)

返回从URL中抽取指定N部分的内容并作为一个元组返回,参数url是URL字符串,而参数p1,p2,....是要抽取的部分

 

2. 函数功能演示

2.1 explode(ARRAY)

功能:返回n行,每行对应数组中的一个元素。

举例:

hive (app)> select explode(array(1,2,3,4));
OK
col
1
2
3
4

2.2 explode(MAP)

功能:返回n行两列,每行对应每个map键-值,第一列是map的键,第二列是map的值。(不常用)

举例:

hive (app)> select explode(map(1,2,3,4));
OK
key	value
1	2
3	4

2.3 posexplode(ARRAY)

功能:与explode类似,但除了数组元素本身(第二列),还返回各元素在数组中的位置(从0开始,第一列)。(不常用)

举例:

hive (app)> select posexplode(array(2,4,6,8));
OK
pos	val
0	2
1	4
2	6
3	8

2.4 stack(INT n, v_1, v_2, ..., v_k)

功能:把k列数据转换成n行,k/n列,其中n必须是正整数,后面的v_1到v_k必须是元素,不能是列名(完全想不到这个函数的用途……)。(不常用)

举例:

n设为3,将后面6个元素按顺序分为3行2列
hive (app)> select stack(3,1,2,3,4,5,6);
OK
col0	col1
1	2
3	4
5	6

n设为2,将后面6个元素按顺序分为2行3列
hive (app)> select stack(2,1,2,3,4,5,6);
OK
col0	col1	col2
1	2	3
4	5	6

n设为6,将后面6个元素转为为6行1列
hive (app)> select stack(6,1,2,3,4,5,6);
OK
col0
1
2
3
4
5
6

2.5 json_tuple(jsonStr, k1, k2, ...)

功能:从一个JSON字符串中获取多个key对应的value并作为一个元组返回。

举例:具体用法见进阶篇(三)

 

2.6 parse_url_tuple(url, p1, p2, ...)

功能:返回从URL中抽取指定N部分的内容并作为一个元组返回,参数url是URL字符串,而参数p1,p2,....是要抽取的部分。

举例:具体用法见进阶篇(四)

 

3. 表生成函数必备:lateral view

UDTF有一个很大的限制,在使用UDTF时,select后面只能跟UDTF,不能跟其他任何字段,否则会报错,如下:

hive (app)> select 1 as flag,explode(array(1,2,3,4));

FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions

lateral view就是为了解决在select使用UDTF做查询过程中,查询只能包含单个UDTF,不能包含其他字段、以及多个UDTF的问题。

lateral view 会将UDTF拆分成多行的结果放到一个支持别名的虚拟表中,然后这个虚拟表会和输入行进行join 来达到连接UDTF外的select字段的目的。

其实在进阶篇(三)和(四)中曾经使用过lateral view,本文来详细介绍下lateral view的具体用法。

3.1 lateral view语法

select 
列别名1[ ,列别名2,列别名3……] 
from 表名 lateral view udtf(expression) 虚拟表别名 as 列别名1[ ,列别名2,列别名3……]

 lateral view跟在from后面,然后跟要使用的UDTF,为生成的虚拟表起一个表别名,不写会报错。然后跟as 列别名,有些UDTF会产生多个列,所以有时要跟多个列别名,比如进阶篇(三、四)中的例子。

3.2 应用1:行转列

现有数据如下:

a 1,2,3
b 4,5,6

想将数据格式转为:

a 1
a 2
a 3
b 4
b 5
b 6

这种展现格式的转换操作就叫做行转列。

 

举例:

新建test.txt文件,输入上文的两列数据,以空格分隔

[root@hadoop ~]# vim test.txt 

a 1,2,3
b 4,5,6

在hive中新建表temp_test6,将test文件中的数据插入,查看数据

CREATE TABLE temp_test6 (
      shop STRING
      ,uid_array STRING
      ) row format delimited fields terminated BY ' ';
 
 
load data local inpath '/root/test.txt' into table temp_test6;
 
select * from temp_test6;

temp_test6.shop	temp_test6.uid_array
a	1,2,3
b	4,5,6

使用lateral view explode和split函数行转列

首先使用split函数对uid_array进行切割,返回一个数组,然后使用lateral VIEW explode进行行转列

SELECT shop
      ,uid   --这里是下面生成的列别名
FROM temp_test6 lateral VIEW explode(split(uid_array, ',')) a AS uid;

shop	uid
a	1
a	2
a	3
b	4
b	5
b	6

3.3 应用2:求总聚合结果

举例:

新建test.txt文件,输入上文的两列数据,以空格分隔

[root@hadoop ~]# vim test.txt 

a 1
a 2
a 4
b 4
b 5
b 6

在hive中新建表temp_test7,将test文件中的数据插入,查看数据。第一列shop是商店名,第二列uid代表来点用户id。

CREATE TABLE temp_test7 (
      shop STRING
      ,uid STRING
      ) row format delimited fields terminated BY ' ';
 
 
load data local inpath '/root/test.txt' into table temp_test7;
 
select * from temp_test7;

temp_test7.shop	temp_test7.uid
a	1
a	2
a	4
b	4
b	5
b	6

此时想一句HQL求出每个商店的来客数,以及两个商店去重后的来客数。由于uid为4的用户同时出现在两家商店,所以统计total维度时用户数为5。最终要得到如下结果:

a     3
b     3
total 5 

使用lateral view explode实现,关键点在于构造一个array数组,将原本的聚合维度字段放入,然后任意自定义一个词例如‘total’作为总聚合的维度名称,再自定义一个别名(这里使用total_shop),代表包含total的字段名,聚合时使用新自定义的别名进行聚合,如下:

SELECT total_shop
      ,count(distinct uid) AS uid_num
FROM temp_test7 lateral VIEW explode(array(shop, 'total')) A AS total_shop
GROUP BY total_shop;

total_shop	uid_num
a	        3
b	        3
total	        5

这样的写法等价于:

SELECT shop
      ,count(DISTINCT uid) AS uid_num
FROM temp_test7
GROUP BY shop

UNION ALL

SELECT 'total' AS shop
      ,count(DISTINCT uid) AS uid_num
FROM temp_test7;

total_shop	uid_num
a	        3
b	        3
total	        5

 


能看到这里的同学,就右上角点个赞吧,3Q~

 

 

你可能感兴趣的:(Hive零基础从入门到实战 进阶篇(十二) HiveQL:表生成函数(行转列))