解决 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 view

    select festival, good_name 
    from tableA
    LATERAL VIEW explode(good_name) v 
    	as good_name;	
    
  • 效果:

festival another_name1
端午 端阳
端午 龙舟
端午 重午
中秋 团圆
中秋 祭月
春节 新春
春节 新岁
春节 岁旦





如果本文对你有帮助的话记得给一乐点个赞哦,感谢!

posted @ 2023-02-27 14:26  一乐乐  阅读(133)  评论(0编辑  收藏  举报