在对于SQL的使用中,常常会遇到列转行,或者将一列的数据散列成多行进行统计分析处理的需求,这时候,结合split()、explode()和lateral view 处理这些需求会使得我们得心应手许多。先来了解一下这三个基本的介绍吧。
Hive集合数据类型
数据类型 | 描述 | 语法示例 |
---|---|---|
struct | 和c语言中的struct类似,都可以通过“点”符号访问元素内容。例如,如果某个列的数据类型是STRUCT{first STRING, last STRING},那么第1个元素可以通过 字段名.first来引用。 | struct |
map | MAP是一组键-值对元组集合,使用数组表示法可以访问数据。例如,如果某个列的数据类型是MAP,其中键->值对是’first’->’John’和’last’->’Doe’,那么可以通过字段名[‘last’]获取最后一个元素 | map(‘first’,‘JOIN’,‘last’,‘Doe’) |
ARRAY | 数组是一组具有相同类型和名称的变量的集合。这些变量称为数组的元素,每个数组元素都有一个编号,编号从零开始。例如,数组值为[‘John’, ‘Doe’],那么第2个元素可以通过数组名[1]进行引用。 | Array() 例如array(‘john’,‘Doe’) |
Hive有三种复杂数据类型ARRAY、MAP 和 STRUCT。ARRAY和MAP与Java中的Array和Map类似,而STRUCT与C语言中的Struct类似,它封装了一个命名字段集合,复杂数据类型允许任意层次的嵌套。
用法:LATERAL VIEW udtf(expression) 虚拟表别名 AS 列别名
在大致了解了split()、explode()和lateral view的介绍我们一一开始去看看是如何使用的。
# 新建一个文本
[qingfeng@hadoop102 data]$vim movie.txt
# 数据如下,电影的分类以及语言
《疑犯追踪》 悬疑,动作,科幻,剧情 English,Chinese,Janpanese,Krease
《Lie to me》 悬疑,警匪,动作,心理,剧情 English,Chinese,Janpanese,Gernemic
《战狼2》 战争,动作,灾难 English,Chinese,Janpanese
-- 创建movie表
hive > create table movie(mname string,category string,language string)
row format delimited fields terminated by '\t';
-- 加载数据
hive > load data local inpath "/home/qingfeng/data/movie.txt" into table movie;
-- 查看数据
hive > select * from movie;
INFO : OK
+----------------+---------------------+-------------------------------------+
| movie.mname | movie.category | movie.language |
+----------------+---------------------+-------------------------------------+
| 《疑犯追踪》 | 悬疑,动作,科幻,剧情 | English,Chinese,Janpanese,Krease |
| 《Lie to me》 | 悬疑,警匪,动作,心理,剧情 | English,Chinese,Janpanese,Gernemic |
| 《战狼2》 | 战争,动作,灾难 | English,Chinese,Janpanese |
+----------------+---------------------+-------------------------------------+
3 rows selected (0.087 seconds)
使用split函数,其结果为array数组,将分割的元素放在数组中。
-- split()
hive> select split(category,',') cate from movie;
+-----------------------------+
| cate |
+-----------------------------+
| ["悬疑","动作","科幻","剧情"] |
| ["悬疑","警匪","动作","心理","剧情"] |
| ["战争","动作","灾难"] |
+-----------------------------+
3 rows selected (0.1 seconds)
使用explode()函数在split基础上对电影分类的这一列转换为多行单个
hive > select explode(split(category,',')) from movie;
+------+
| col |
+------+
| 悬疑 |
| 动作 |
| 科幻 |
| 剧情 |
| 悬疑 |
| 警匪 |
| 动作 |
| 心理 |
| 剧情 |
| 战争 |
| 动作 |
| 灾难 |
+------+
12 rows selected (0.075 seconds)
当我们需要将电影名称和对应的分类对应显示,我们应该怎么做?
结果形如:
《疑犯追踪》 悬疑
《疑犯追踪》 动作
《疑犯追踪》 科幻
《疑犯追踪》 剧情
《Lie to me》 悬疑
《Lie to me》 警匪
《Lie to me》 动作
《Lie to me》 心理
《Lie to me》 剧情
《战狼2》 战争
《战狼2》 动作
《战狼2》 灾难
我们在explode查询基础上添加mname字段,是否可以呢?
hive> select mname,explode(split(category,',')) cate from movie;
Error: Error while compiling statement: FAILED: SemanticException [Error 10081]:
UDTF's are not supported outside the SELECT clause,
nor nested in expressions (state=42000,code=10081)
报错了,提示我们不支持在select外部使用UDTF函数,这个时候lateral view就可以配合一起使用了,lateral view我们也称之为侧写。
-- 结合lateral view 查看
select mname,cate
from movie
lateral view explode(split(category,',')) tmp as cate;
+--------------+-------+
| mname | cate |
+--------------+-------+
| 《疑犯追踪》 | 悬疑 |
| 《疑犯追踪》 | 动作 |
| 《疑犯追踪》 | 科幻 |
| 《疑犯追踪》 | 剧情 |
| 《Lie to me》 | 悬疑 |
| 《Lie to me》 | 警匪 |
| 《Lie to me》 | 动作 |
| 《Lie to me》 | 心理 |
| 《Lie to me》 | 剧情 |
| 《战狼2》 | 战争 |
| 《战狼2》 | 动作 |
| 《战狼2》 | 灾难 |
+--------------+-------+
12 rows selected (0.047 seconds)
当我们需要对于category 列和language列一起散列,只需要对每一个需要操作的列进行lateral view即可。
需求是想要如下的显示格式:
+--------------+-------+------------+
| mname | cate | lang |
+--------------+-------+------------+
| 《疑犯追踪》 | 悬疑 | English |
| 《疑犯追踪》 | 悬疑 | Chinese |
| 《疑犯追踪》 | 悬疑 | Janpanese |
| 《疑犯追踪》 | 悬疑 | Krease |
| 《疑犯追踪》 | 动作 | English |
| 《疑犯追踪》 | 动作 | Chinese |
| 《疑犯追踪》 | 动作 | Janpanese |
| 《疑犯追踪》 | 动作 | Krease |
| 《疑犯追踪》 | 科幻 | English |
| 《疑犯追踪》 | 科幻 | Chinese |
| 《疑犯追踪》 | 科幻 | Janpanese |
| 《疑犯追踪》 | 科幻 | Krease |
| 《疑犯追踪》 | 剧情 | English |
| 《疑犯追踪》 | 剧情 | Chinese |
| 《疑犯追踪》 | 剧情 | Janpanese |
| 《疑犯追踪》 | 剧情 | Krease |
| 《Lie to me》 | 悬疑 | English |
则其对应的查询sql如下:
hive> select mname,cate,lang from movie lateral view explode(split(category,',')) tmp as cate lateral view explode(split(language,',')) tmp as lang;
+--------------+-------+------------+
| mname | cate | lang |
+--------------+-------+------------+
| 《疑犯追踪》 | 悬疑 | English |
| 《疑犯追踪》 | 悬疑 | Chinese |
| 《疑犯追踪》 | 悬疑 | Janpanese |
| 《疑犯追踪》 | 悬疑 | Krease |
| 《疑犯追踪》 | 动作 | English |
| 《疑犯追踪》 | 动作 | Chinese |
| 《疑犯追踪》 | 动作 | Janpanese |
| 《疑犯追踪》 | 动作 | Krease |
| 《疑犯追踪》 | 科幻 | English |
| 《疑犯追踪》 | 科幻 | Chinese |
| 《疑犯追踪》 | 科幻 | Janpanese |
| 《疑犯追踪》 | 科幻 | Krease |
| 《疑犯追踪》 | 剧情 | English |
| 《疑犯追踪》 | 剧情 | Chinese |
| 《疑犯追踪》 | 剧情 | Janpanese |
| 《疑犯追踪》 | 剧情 | Krease |
| 《Lie to me》 | 悬疑 | English |
| 《Lie to me》 | 悬疑 | Chinese |
| 《Lie to me》 | 悬疑 | Janpanese |
| 《Lie to me》 | 悬疑 | Gernemic |
| 《Lie to me》 | 警匪 | English |
| 《Lie to me》 | 警匪 | Chinese |
| 《Lie to me》 | 警匪 | Janpanese |
| 《Lie to me》 | 警匪 | Gernemic |
| 《Lie to me》 | 动作 | English |
| 《Lie to me》 | 动作 | Chinese |
| 《Lie to me》 | 动作 | Janpanese |
| 《Lie to me》 | 动作 | Gernemic |
| 《Lie to me》 | 心理 | English |
| 《Lie to me》 | 心理 | Chinese |
| 《Lie to me》 | 心理 | Janpanese |
| 《Lie to me》 | 心理 | Gernemic |
| 《Lie to me》 | 剧情 | English |
| 《Lie to me》 | 剧情 | Chinese |
| 《Lie to me》 | 剧情 | Janpanese |
| 《Lie to me》 | 剧情 | Gernemic |
| 《战狼2》 | 战争 | English |
| 《战狼2》 | 战争 | Chinese |
| 《战狼2》 | 战争 | Janpanese |
| 《战狼2》 | 动作 | English |
| 《战狼2》 | 动作 | Chinese |
| 《战狼2》 | 动作 | Janpanese |
| 《战狼2》 | 灾难 | English |
| 《战狼2》 | 灾难 | Chinese |
| 《战狼2》 | 灾难 | Janpanese |
+--------------+-------+------------+
45 rows selected (0.052 seconds)
从结果可以看出,多个列进行lateral view就是各自的explode做了全连接。
explode函数一般是与lateral view结合使用,因为我们在实际业务中不会单独查看一个列散列之后的情况。同时也从多列explode可以看出,多列的结果是各个列的全连接。