本文部分參考自:https://blog.csdn.net/qq_23897391/article/details/98724777
Hive第五天——Hive函數
自己的話:千里之行,始於足下。
每天都要保持前進,我勢必要有強勁的實力,再跟明天的自己問好。
表生成函數(行轉列)
一、表生成函數簡介
在Hive中,所有的表生成函數,包括用戶自定義的和內置的,都統稱爲用戶自定義表生成函數(user defined table generating functions),簡稱UDTF。本文只介紹Hive自帶的內置表生成函數。
二、函數功能演示
1.explode(ARRAY)
(1)功能:
返回n行,每行對應數組中的一個元素。
(2)舉例:
hive (app)> select explode(array(1,2,3,4));
OK
col
1
2
3
4
<1>編輯數據:
vi sutdent.txt
1,zhangsan,數學:語文:英語:生物
2,lisi,數學:語文
3,wangwu,化學:計算機:java
<2>創建表:
hive> create table t_xuanxiu(uid string,name string,kc array<string>)
>row format delimited
>fields terminated by ','
>collection items terminated by ':';
<3>加載數據並查看:
hive> load data local inpath "/home/student.txt" into table t_xuanxiu;
hive> select uid,name,kc[0] from t_xuanxiu; #kc[0]查看的是數組的第一個元素
<4>將一個數組變成列:
hive> select explode(kc) from t_xuanxiu where uid=1;
2.explode(MAP)
(1)功能:
返回n行兩列,每行對應每個map鍵-值,第一列是map的鍵,第二列是map的值。(不常用)
(2)舉例:
hive (app)> select explode(map(1,2,3,4));
OK
key value
1 2
3 4
3.json_tuple(jsonStr, k1, k2, …)
(1)功能:
從一個JSON字符串中獲取多個key對應的value並作爲一個元組返回。
(2)舉例:
具體用法見 Hive函數(JSON解析函數)
4.parse_url_tuple(url, p1, p2, …)
(1)功能:
返回從URL中抽取指定N部分的內容並作爲一個元組返回,參數url是URL字符串,而參數p1,p2,…是要抽取的部分。
(2)舉例:
具體用法見 Hive函數(URL解析函數)
還有許多不常用的函數,很少碰見,就不詳述了。
三、表生成函數必備: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字段的目的。
1.lateral view語法
select
列別名1[ ,列別名2,列別名3……]
from 表名 lateral view udtf(expression) 虛擬表別名 as 列別名1[ ,列別名2,列別名3……]
lateral view跟在from後面,然後跟要使用的UDTF,爲生成的虛擬表起一個表別名,不寫會報錯。然後跟as 列別名,有些UDTF會產生多個列,所以有時要跟多個列別名,比如JSON和URL解析的例子。
2. 應用:行轉列
(1)需求:
現有數據如下:
a 1,2,3
b 4,5,6
想將數據格式轉爲:
a 1
a 2
a 3
b 4
b 5
b 6
這種展現格式的轉換操作就叫做行轉列。
(2)舉例1:
<1>新建test.txt文件,輸入上文的兩列數據,以空格分隔
[root@hadoop ~]# vim test.txt
a 1,2,3
b 4,5,6
<2>在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
<3>使用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)舉例2:
上面寫到的學生選修學科,學科在表中是一個數組
<1>需求:
1,zhangsan,數學
1,zhangsan,語文
1,zhangsan,英語
1,zhangsan,生物
2,lisi,數學
2,lisi,語文
id和拆分的array元素是對應的.我們應該如何進行連接呢?我們知道直接select id,explode()是不行的.這個時候就需要lateral view出廠了.
<2>使用lateral view和explode函數行轉列
hive>select uid,name,tmp.course from t_xuanxiu
>lateral view explode(kc) tmp as course;
<3>解釋:
lateral view 將 explode(kc) 看成一個表是 tmp 就一個字段as course;
3.應用:求總聚合結果
舉例:
(1)新建test.txt文件,輸入上文的兩列數據,以空格分隔
[root@hadoop ~]# vim test.txt
a 1
a 2
a 4
b 4
b 5
b 6
(2)在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
(3)此時想一句HQL求出每個商店的來客數,以及兩個商店去重後的來客數。由於uid爲4的用戶同時出現在兩家商店,所以統計total維度時用戶數爲5。最終要得到如下結果:
a 3
b 3
total 5
(4)使用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
(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
這就是Hive函數中的表生成函數,主要用於行轉列