一文学会Hive解析Json数组

大数据 2023-07-05 17:29:38
740阅读

在Hive中会出现许多 数据信息是用Json文件格式来储存的,如开发者对APP上的网页页面开展埋点时,会将好几个字段名储放在一个json二维数组中,因而大数据平台启用数据信息时,要对埋点数据信息开展分析。下面就聊一聊Hive中是怎样分析json数据信息的。

Hive内置的json解析函数

1. get_json_object

  • 英语的语法:get_json_object(json_string, '$.key')
  • 表明:分析json的字符串数组json_string,回到path特定的內容。假如键入的json字符串数组失效,那麼回到NULL。这一涵数每一次只有回到一个数值数据。
  • 实例:
    select  
    get_json_object('{"name":"zhangsan","age":18}','$.name');  

結果:

name
zhangsan

假如既要分析name字段名,也分析age字段名,则能够那样写:

select  
get_json_object('{"name":"zhangsan","age":18}','$.name'), 
get_json_object('{"name":"zhangsan","age":18}','$.age'); 

可是假如要分析的字段名有很多,再那样写就太麻烦了,因此 就拥有 json_tuple 这一涵数。

2. json_tuple

  • 英语的语法:json_tuple(json_string, k1, k2 ...)
  • 表明:分析json的字符串数组json_string,可特定好几个json数据信息中的key,回到相匹配的value。假如键入的json字符串数组失效,那麼回到NULL。
  • 实例:
    select  
    b.name 
    ,b.age 
    from tableName a lateral view 
    json_tuple('{"name":"zhangsan","age":18}','name','age') b as name,age; 
  • 結果:
name age
zhangsan 18

留意:上边的json_tuple涵数中沒有$.

假如在应用json_tuple涵数时再加上$.便会分析不成功:

select  
b.name 
,b.age 
from tableName a lateral view 
json_tuple('{"name":"zhangsan","age":18}','$.name','$.age') b as name,age; 

結果:

name age
NULL NULL

字段名都是NULL,因此 json_tuple涵数不用加$.了,不然会分析不上。

小结:json_tuple等同于get_json_object的优点便是一次能够分析好几个json字段名。可是如果我们有一个json二维数组,这两个涵数都没法解决。

Hive分析json二维数组

一、嵌入子查询分析json二维数组

假如有一个hive表,表格中 json_str 字段名的內容以下:

json_str
[{"website":"baidu.com","name":"百度搜索"},{"website":"google.com","name":"Google"}]

大家想把这个字段名分析出去,产生以下的构造:

website name
baidu.com 百度搜索
google.com Google

要分析这一json二维数组,仅用上边详细介绍的2个涵数就分析不出来,还要用到以下详细介绍的好多个涵数:

explode涵数

  • 英语的语法:explode(Array OR Map)
  • 表明:explode()涵数接受一个array或是map种类的数据信息做为键入,随后将array或map里边的原素依照每排的方式輸出,将要hive一列中繁杂的array或是map构造拆分为几行表明,也被称作列转行涵数。
  • 实例:
    -- 分析array 
    hive> select explode(array('A','B','C')); 
    OK 
    A 
    B 
    C 
    
    
    -- 分析map 
    hive> select explode(map('A',10,'B',20,'C',30)); 
    OK 
    A       10 
    B       20 
    C       30 

regexp_replace涵数

  • 英语的语法: regexp_replace(string A, string B, string C)
  • 表明:将字符串数组A中的合乎java正则表达式B的一部分更换为C。留意,在有一些状况下需要应用转义字符,相近oracle中的regexp_replace涵数。
  • 实例:
  1. hive> select regexp_replace('foobar''oo|ar''');  
  2. OK 
  3. fb 

以上实例将字符串数组中的 oo 或 ar 更换为''。

拥有以上好多个涵数,下面大家来分析json_str字段名的內容:

先将json二维数组中的原素分析出去,转换为每排表明:

hive> SELECT explode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度搜索"},{"website":"google.com","name":"Google"}]', '\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')); 
OK 
{"website":"baidu.com","name":"百度搜索"} 
{"website":"google.com","name":"Google"} 

对以上sql开展简要说明:

SELECT explode(split( 
    regexp_replace( 
        regexp_replace( 
            '[ 
                {"website":"baidu.com","name":"百度搜索"}, 
                {"website":"google.com","name":"Google"} 
            ]',  
            '\\[|\\]' , ''), 将json二维数组两侧的中括号除掉 
             
              '\\}\\,\\{' , '\\}\\;\\{'), 将json二维数组原素中间的分号换成份号 
                 
                 '\\;') 以分号做为分节符(split涵数以分号做为隔开) 
          );   

为何要将json二维数组原素中间的分号换成份号?

由于原素内的隔开也是分号,如果不将原素中间的分号更换得话,后边用split涵数隔开时也会把原素内的数据信息给隔开,这不是大家要想的結果。

上步早已把一个json二维数组转换为好几个json字符串数组了,下面融合son_tuple涵数来分析json里边的字段名:

select  
json_tuple(explode(split( 
regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度搜索"},{"website":"google.com","name":"Google"}]', '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))  
) , 'website', 'name') ; 

实行以上句子,結果出错了:

FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions 

意思是UDTF涵数不可以写在其他涵数内,也就是这儿的explode涵数不可以写在json_tuple里边。

即然explode涵数不可以写在其他json_tuple里边,那大家可以用子查询方法,以下所显示:

select json_tuple(json, 'website', 'name')  
from ( 
select explode(split(regexp_replace(regexp_replace('[{"website":"baidu.com","name":"百度搜索"},{"website":"google.com","name":"Google"}]', '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))  
as json) t; 

实行以上句子,沒有出错,实行結果以下:

www.baidu.com   百度搜索 
google.com      Google 

二 应用 lateral view 分析json二维数组

hive表格中 goods_id 和 json_str 字段名的內容以下:

goods_id json_str
1,2,3 [{"source":"7fresh","monthSales":4900,"userCount":1900,"score":"9.9"},{"source":"jd","monthSales":2090,"userCount":78981,"score":"9.8"},{"source":"jdmart","monthSales":6987,"userCount":1600,"score":"9.0"}]

目地:把 goods_id 字段名和 json_str 字段名中的monthSales分析出去。

下边大家就逐渐分析:

分拆goods_id字段名及将json二维数组转换成好几个json字符串数组:

select  
explode(split(goods_id,',')) as good_id, 
explode(split(regexp_replace(regexp_replace(json_str , '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;'))  
as sale_info  
from tableName; 

实行以上句子,結果出错:

FAILED: SemanticException 3:0 Only a single expression in the SELECT clause is supported with UDTF's. Error encountered near token 'sale_info' 

意思是用UDTF的情况下,SELECT 只适用一个字段名。而以上句子select中有两个字段名,因此 出错了。

那怎么办呢,要处理这个问题,还得再详细介绍一个hive英语的语法:

lateral view

lateral view用以和split、explode等UDTF一起应用的,能将一行数据信息拆分为几行数据信息,在这个基础上能够对分拆的数据信息开展汇聚,lateral view最先为初始表的每排启用UDTF,UDTF会把一行拆分为一行或是几行,lateral view在把結果组成,造成一个适用别称表的虚似表。

  • 实例:

假定大家有一张客户个人爱好表 hobbies_table,它有多列数据信息,第一列是name,第二列是客户兴趣爱好爱好的id_list,是一个二维数组,储存兴趣爱好爱好的id值:

name id_list
zhangsan [1,2,3]
lisi [3,4,5]

我们要统计分析全部兴趣爱好id在全部客户中发生的频次:

对兴趣爱好id开展分析:

SELECT name, hobby_id  
FROM hobbies_table  
LATERAL VIEW explode(id_list) tmp_table AS hobby_id; 

以上sql实行結果:

name hobby_id
zhangsan 1
zhangsan 2
zhangsan 3
lisi 3
lisi 4
lisi 5

2. 依照hobby_id开展排序汇聚就可以:

SELECT hobby_id ,count(1) client_num 
FROM hobbies_table  
LATERAL VIEW explode(id_list) tmp_table AS hobby_id 
group by hobby_id; 

結果:

hobby_id client_num
1 1
2 1
3 2
4 1
5 1

详细介绍完 lateral view 以后,大家再说处理上边碰到的用UDTF的情况下,SELECT 只适用一个字段名的难题:

select good_id,get_json_object(sale_json,'$.monthSales') as monthSales 
from tableName  
LATERAL VIEW explode(split(goods_id,','))goods as good_id  
LATERAL VIEW explode(split(regexp_replace(regexp_replace(json_str , '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')) sales as sale_json; 

留意:以上句子是三个表笛卡尔积的結果,因此 此方法适用信息量并不是非常大的状况。

以上句子实行結果以下:

goods_id monthSales
1 4900
1 2090
1 6987
2 4900
2 2090
2 6987
3 4900
3 2090
3 6987

假如表格中也有别的字段名,我们可以依据别的字段名挑选出合乎結果的数据信息。

小结:lateral view一般和UDTF一起发生,为了更好地处理UDTF不允许在select存有好几个字段名的难题。

 
the end
免责声明:本文不代表本站的观点和立场,如有侵权请联系本站删除!本站仅提供信息存储空间服务。