大数据的 ETL(Extract-Transfer-Load) 过程的 Transfer 阶段,需要对 json 串数据进行转换“拍平”处理。
亲测!超好用 Hive 内置的 json 解析函数 一文中详细介绍过 get_json_object 和 json_tuple 函数如何对 json 串进行有效解析,但美中不足的是这两个函数都无法解析 json 数组,只能解析单个 json 串。
今天的分享将会介绍 Hive 中常用于 json 数组的解析函数及详细使用方法。
数据准备
例如:Hive中有一张 test_json 表,表中 json_data 字段的内容如下:
| json_data |
|---|
| [{"user_id":"1","name":"小琳","age":16},{"user_id":"2","name":"小刘","age":18},{"user_id":"3","name":"小明","age":20}] |
基于以上的 json_data 数据,现需要将以上 json 串数据解析为如下结构数据:
| user_id | name | age |
|---|---|---|
| 1 | 小琳 | 16 |
| 2 | 小刘 | 18 |
| 3 | 小明 | 20 |
在进行解析之前,先来了解下面两个函数的使用方法。
函数运用
1. explode函数
语法
explode(Array|Map)
说明
explode()函数接收一个 array 或者 map 类型的数据作为输入,然后将 array 或 map 里面的元素按照每行的形式输出。
即将 Hive 一列中复杂的 array 或者 map 结构拆分成多行显示,也被称为列转行函数。
举例
array测试sql语句:
select explode(array('user_id','name','age'));
执行结果:

map测试sql语句:
select explode(map('user_id',1,'name','rocky','age',18));
执行结果:

2. regexp_replace函数
语法
regexp_replace(str A, str B, str C)
说明
语法含义:将字符串 A 中的符合正则表达式 B 的部分替换为 C。
注意:当字符串 A 中有一些特殊字符时,在正则表达式 B 中要使用转义字符。
举例
sql语句:
select regexp_replace('hello world!', '\\ |\\!', '');
执行结果:

3. 具体函数运用
了解 explode 函数与 regexp_replace 函数的使用规则后,现在来完成上面数据准备中提出的解析需求。
第一步解析:json数组拆分成多行
sql语句:
SELECT explode(split(
regexp_replace(
regexp_replace(
'[
{"user_id":"1","name":"小琳","age":16},
{"user_id":"2","name":"小刘","age":18},
{"user_id":"3","name":"小明","age":20}
]',
'\\[|\\]' , ''), 将json数组两边的中括号去掉
'\\}\\,\\{' , '\\}\\;\\{'), 将json数组元素之间的逗号换成分号
'\\;') 以分号作为分隔符(split函数以分号作为分隔)
);
执行结果:

第二步解析:json数组key转列字段
sql语句:
select json_tuple(json, 'user_id', 'name', 'age')
from (select explode(split(
regexp_replace(
regexp_replace(
'[
{"user_id":"1","name":"小琳","age":16},
{"user_id":"2","name":"小刘","age":18},
{"user_id":"3","name":"小明","age":20}
]',
'\\[|\\]' , ''),
'\\}\\,\\{' , '\\}\\;\\{'),
'\\;')
)as json) tmp;
执行结果:

数据准备
例如:
Hive中有一张 data_json 表,表中 goods_id 和 str_data 字段的内容如下:
| goods_id | str_data |
|---|---|
| 5,7,9 | [{"source":"taobao","sold":100,"remain":1000},{"source":"jd","sold":200,"remain":2000},{"source":"meituan","sold":300,"remain":3000}] |
基于以上的 goods_id 和 str_data 数据,现需要将以上 json 串数据解析为如下结构数据:
| goods_id | sold |
|---|---|
| 5 | 100 |
| 5 | 200 |
| 5 | 300 |
| 7 | 100 |
| 7 | 200 |
| 7 | 300 |
| 9 | 100 |
| 9 | 200 |
| 9 | 300 |
在进行解析之前,先来了解下面两个函数的使用方法。
函数运用
1. lateral view函数
说明
lateral view 用于和 split, explode 等 UDTF 一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合。
lateral view 首先为原始表的每行调用 UDTF,UDTF 会把一行拆分成一行或者多行,lateral view 在把结果组合,产生一个支持别名表的虚拟表。
举例
例如:Hive 中有一张 page_ads 表,表数据结构如下:
| page_name | ads_id |
|---|---|
| home_page | [1,2,3] |
| front_page | [2,6] |
page_name 代表页面名称,ads_id 代表投放广告的所属 id,多个 id之间使用逗号分隔。
需求:统计所有广告 id 在所有页面中出现的次数。
第一步解析:拆分广告id
拆分sql语句:
SELECT page_name, ads_id
FROM page_ads LATERAL VIEW explode(ads_id) adTable AS adid;
拆分结果:
| page_name | ads_id |
|---|---|
| home_page | 1 |
| home_page | 2 |
| home_page | 3 |
| front_page | 2 |
| front_page | 6 |
第二步解析:聚合统计
聚合统计sql语句:
SELECT adid, count(1)
FROM page_ads LATERAL VIEW explode(ads_id) adTable AS adid
GROUP BY adid;
统计结果:
| adid | count(1) |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
| 6 | 1 |
2. 具体函数运用
解析 data_json 表的sql语句如下:
select goods_id,get_json_object(sale_json,'$.sold') as sold
from data_json
LATERAL VIEW explode(split(goods_id,','))goods as goods_id
LATERAL VIEW explode(split(
regexp_replace(
regexp_replace(json_str , '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')) sales as sale_json;
注意:
上述语句是 3*3 笛卡尔积的结果,所以此方式适用于数据量不是很大的情况。
执行结果如下:
| goods_id | sold |
|---|---|
| 5 | 100 |
| 5 | 200 |
| 5 | 300 |
| 7 | 100 |
| 7 | 200 |
| 7 | 300 |
| 9 | 100 |
| 9 | 200 |
| 9 | 300 |
欢迎关注【无量测试之道】公众号,回复【领取资源】
Python+Unittest框架API自动化、
Python+Unittest框架API自动化、
Python+Pytest框架API自动化、
Python+Pandas+Pyecharts大数据分析、
Python+Selenium框架Web的UI自动化、
Python+Appium框架APP的UI自动化、
Python编程学习资源干货、
Vue前端组件化框架开发、
资源和代码 免费送啦~
文章下方有公众号二维码,可直接微信扫一扫关注即可。
备注:我的个人公众号已正式开通,致力于IT互联网技术的分享。
包含:数据分析、大数据、机器学习、测试开发、API接口自动化、测试运维、UI自动化、性能测试、代码检测、编程技术等。
微信搜索公众号:“无量测试之道”,或扫描下方二维码:

添加关注,让我们一起共同成长!
我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我正在使用ruby1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re