解决 FAILED: UDFArgumentException explode() takes an array or a map as a parameter 并理解炸裂函数和侧视图
一、解决 FAILED: UDFArgumentException explode() takes an array or a map as a parameter
1、背景
项目中数据处理后,进行查询得到的所有结果如下,其中 genre 字段类型,其实是一个字符串(业务逻辑处理后的结果),可视化展示,看着像一个数组而已
SELECT
get_json_object(map_col,'$.game_name') game_name,
get_json_object(map_col,'$.genre') genre
FROM
ods_crawler_table
WHERE
dt = '2023-02-26'
AND get_json_object(map_col,'$.code') = 'xxx'
2、接下来想要使用explode 函数,对genre 字段进行一行转成多行
SELECT
explode(get_json_object(map_col,'$.genre')) genre
FROM
ods_crawler_table
WHERE
dt = '2023-02-26'
AND get_json_object(map_col,'$.code') = 'xxx'
3、报错
错误信息:FAILED: UDFArgumentException explode() takes an array or a map as a parameter
4、分析原因:
① 这个genre 只是表面看着是数组,其实它在业务处理后,实际上是一个String 类型
② 并且是一个带有多余的[]的String 类型的
③ 需要处理成数组类型,前提是先把多余的[] 去掉,然后,使用String的split 方法进行切割后返回的即是一个数组
split(regexp_replace(get_json_object(map_col,'$.genre'), '\\[|\\]', ''), ",")
------------------------------------------------------------------------------------------------------------------
SELECT
split(regexp_replace(get_json_object(map_col,'$.genre'), '\\[|\\]', ''), ",") genre
FROM
ods_crawler_table
WHERE
dt = '2023-02-26'
AND get_json_object(map_col,'$.code') = 'xxx'
结果如下:
再试试炸裂函数explode 效果:
SELECT
explode(split(regexp_replace(get_json_object(map_col,'$.genre'), '\\[|\\]', ''), ",")) genre
FROM
ods_crawler_table
WHERE
dt = '2023-02-26'
AND get_json_object(map_col,'$.code') = 'xxx'
至此成功炸裂~~~~~~~~~~~~~
5、explode(genre) 和其他字段一起查询
- 实际业务,字段game_name,genre 都要查询
SELECT
get_json_object(map_col,'$.game_name') game_name,
explode(split(regexp_replace(get_json_object(map_col,'$.genre'), '\\[|\\]', ''), ",")) genre
FROM
ods_crawler_table
WHERE
dt = '2023-02-26'
AND get_json_object(map_col,'$.code') = 'xxx'
报错:
- 报错信息:UDTF's are not supported outside the SELECT clause, nor nested in expressions
分析:原因是因为这个字段genre,炸裂之后,转换成多列(3列),而game_name 字段依然是1列,列数不匹配
解决:侧视图(表)的聚合
ods_crawler_table -- 原先的表
LATERAL VIEW -- 聚合(本质上就是笛卡尔乘积)
explode(split(regexp_replace(get_json_object(map_col,'$.genre'), '\\[|\\]', ''), ",")) v -- 炸裂后作为一个表,两个表聚合之后成v表
as genre -- 是炸裂函数explode(split(regexp_replace(get_json_object(map_col,'$.genre'), '\\[|\\]', ''), ","))的别名
------------------------------------------------------------------------------------------------------------------------
SELECT
get_json_object(map_col,'$.game_name') game_name,
genre
FROM
ods_crawler_table
LATERAL VIEW explode(split(regexp_replace(get_json_object(map_col,'$.genre'), '\\[|\\]', ''), ",")) v as genre
WHERE
dt = '2023-02-26'
AND get_json_object(map_col,'$.code') = 'xxx'
聚合效果:
小细节:lateral view+explode,一起使用后,有两个别名
-
第一个别名是两个表聚合的别名,第二个别名是炸裂函数的别名
-
语法
tableA LATERAL VIEW -- 聚合 explode(fieldB) v -- v 别名:tableA 和自身表使用了explode函数后得到的那个表,进行聚合后得到的新表 as b -- b 别名:explode函数使用后起的别名
二、理解炸裂函数和侧视图
1、explode :
(1) 作用:一行数据转换成多列数据,用于array和map类型的数据。
(2) 语法和例子:
explode (array)
-- 炸裂字段array('A','B','C')
select explode(array('A','B','C')) as col;
col |
---|
A |
B |
C |
explode (map)
-- 炸裂字段 map('A', 10, 'B',10, 'C',10)
select explode(map('A', 10, 'B',10, 'C',10)) as (key, value);
key | value |
---|---|
A | 10 |
B | 20 |
C | 30 |
posexplode (array)
select posexplode(array('A','B','C')) as (pos,val);
pos | val |
---|---|
0 | A |
1 | B |
2 | C |
(3) 炸裂函数的不足:
炸裂某个字段之后,该字段和表其余字段的列数不匹配了,炸裂的字段不能和表的其他字段进行联合查询了。
解决:侧视图lateral view
2、lateral view
(1) 作用:结合UDTF一起使用,解决单独使用UDTF函数不能添加额外的select列的问题。
lateral view会将UDTF生成的结果放到一个虚拟表中,然后这个虚拟表会和输入行进行join来达到连接UDTF外的select字段的目的。
(2) 语法和例子:
□ 语法:
tableA
LATERAL VIEW -- 聚合
explode(fieldB) v -- v 别名:tableA 和自身表使用了explode函数后得到的那个表,进行聚合后得到的新表
as b -- b 别名:explode函数使用后起的别名
□ 例子:
原表格t查询结果如下:
select festival,good_name from tableA;
festival | good_name |
---|---|
端午 | 端阳,龙舟,重午 |
中秋 | 团圆,祭月 |
春节 | 新春,新岁,岁旦 |
-- 使用explode 函数
select explode(good_name) as good_name from tableA;
good_name |
---|
端阳 |
龙舟 |
重午 |
团圆 |
祭月 |
新春 |
新岁 |
岁旦 |
-
想实现的效果:节日名称和别名聚合,在使用explode 函数的时候,直接和字段festival 一起查询
会报错
select festival, explode(another_name) from tableA;
-
报错
:UDTF's are not supported outside the SELECT clause, nor nested in expressions,意思:explode(UDTF),不能直接和其他字段一起使用。 -
解决
:使用 lateral viewselect festival, good_name from tableA LATERAL VIEW explode(good_name) v as good_name;
-
效果:
festival | another_name1 |
---|---|
端午 | 端阳 |
端午 | 龙舟 |
端午 | 重午 |
中秋 | 团圆 |
中秋 | 祭月 |
春节 | 新春 |
春节 | 新岁 |
春节 | 岁旦 |
如果本文对你有帮助的话记得给一乐点个赞哦,感谢!
本文来自博客园,作者:一乐乐,转载请注明原文链接:https://www.cnblogs.com/shan333/p/17159546.html