一、解决 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 view
select festival, good_name from tableA LATERAL VIEW explode(good_name) v as good_name;
- 效果:
festival | another_name1 |
端午 | 端阳 |
端午 | 龙舟 |
端午 | 重午 |
中秋 | 团圆 |
中秋 | 祭月 |
春节 | 新春 |
春节 | 新岁 |
春节 | 岁旦 |
如果本文对你有帮助的话记得给一乐点个赞哦,感谢!