Hive对JSON格式的支持研究
一、背景
JSON是一种通用的存储格式,在半结构化存储中十分常见,部分场景已经开始存在以JSON格式贴源存储的数据,作为下游数据使用方,我们亟需对JSON格式的数据进行加工和处理,以提取出我们需要的数据,以对外提供更完善的数据服务。
经过调研,目前hive已对JSON格式的数据提供了相应的支持,但在一些复杂场景可能无法达到我们的需求以及理想的性能,具体介绍如下。
二、解析JSON对象的方法
(一)get_json_object(string json_string, string path)
- 返回值:String
- 说明:解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NUll,这个函数每次只能返回一个数据项。
- 测试a:
--1 测试get_json_object()
select get_json_object('{"name":"小明","age":"18"}','$.name');
输出:小明
- 测试b:
数据json.txt
{"movie":"1193","rate":"5","timeStamp":"978300760","uid":"1"}
{"movie":"661","rate":"3","timeStamp":"978302109","uid":"1"}
{"movie":"914","rate":"3","timeStamp":"978301968","uid":"1"}
{"movie":"3408","rate":"4","timeStamp":"978300275","uid":"1"}
{"movie":"2355","rate":"5","timeStamp":"978824291","uid":"1"}
{"movie":"1197","rate":"3","timeStamp":"978302268","uid":"1"}
{"movie":"1287","rate":"5","timeStamp":"978302039","uid":"1"}
{"movie":"2804","rate":"5","timeStamp":"978300719","uid":"1"}
{"movie":"594","rate":"4","timeStamp":"978302268","uid":"1"}
create table json(data string);
load data local inpath '/home/hadoop/json.txt' into table json;
select * from json;
select get_json_object(data,'$.movie') as movie from json;
输出:

- 限制
该方法只能返回一个JSON属性的数据,不能同时返回多个。若为了获取多个JSON属性的数据而多次调用get_json_object方法,相当于对JSON数据进行重复多次解析,性能会有所损耗。那么,是否有一个方法能够解析一次JSON数据,返回多个JSON属性的数据呢?有,那就是json_tuple()。
(二)json_tuple(jsonStr, k1, k2, ...)
- 返回值:tuple
- 说明:参数为json字符串和一组键k1,k2,…,返回值的元组。因为可以在一次调用中输入多次键,一次可以解析多个Json字段,因此该方法比get_json_object高效。
- 测试:
select b.b_movie,b.b_rate,b.b_timeStamp,b.b_uid from json a lateral view
json_tuple(a.data,'movie','rate','timeStamp','uid') b as b_movie,b_rate,b_timeStamp,b_uid;
- 限制
该方法和上面介绍的get_json_object()方法都无法对JSON数组进行解析。我们将在第三节对JSON数组的解析进行专题介绍。
(三)自定义函数解析json对象
- 自定义函数
1.
2. package com.data;
3.
4. import org.apache.commons.lang3.StringUtils;
5. import org.apache.hadoop.hive.ql.exec.UDF;
6. import org.json.JSONException;
7. import org.json.JSONObject;
8. import org.json.JSONTokener;
9.
10. /**
11. *
12. * add jar jar/getJsonObjectUDF.jar;
13. * create temporary function getJsonObject as 'com.data.JsonObjectParsing';
14. * Json对象解析UDF
15. * @Author:
16. * @Date: 2020/9/25
17. */
18. public class JsonObjectParsing extends UDF {
19. public static String evaluate(String jsonStr, String keyName) throws JSONException {
20. if(StringUtils.isBlank(jsonStr) || StringUtils.isBlank(keyName)){
21. return null;
22. }
23. JSONObject jsonObject = new JSONObject(new JSONTokener(jsonStr));
24. Object objValue = jsonObject.get(keyName);
25. if(objValue==null){
26. return null;
27. }
28. return objValue.toString();
29. }
30. }
- 测试:
--1 将getJsonObjectUDF.jar上传到hdfs
source ${HADOOP_CLIENT}/bigdata_env
kinit -k etluser/hadoop -t ${WORK_ROOT}/etl_tools/config/etluser.keytab
hadoop fs -rm -f -r /user/etluser/pgm/tempUDF
hadoop fs -mkdir -f -r /user/etluser/pgm/tempUDF
hdsoop fs -put ${WORK_ROOT}/pgm/tempUDF/getJsonObjectUDF.jar /user/etluser/pgm/tempUDF/
--2 创建临时函数getJsonObject()
use udf;
set hive.security.temporary.function.need.admin=false;
create temporary function getJsonObject as 'com.data.JsonObjectParsing' using jar '/user/etluser/pgm/tempUDF/getJsonObjectUDF.jar';
--3 建表db.json
DROP TABLE IF EXISTS DB.JSON;
CREATE TABLE IF NOT EXISTS DB.JSON (
JSON_DATA STRING COMMENT 'json'
)
COMMENT 'hive json'
PARTITIONED BY (pt_dt STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\27'
STORED AS TEXTFILE;
--4 插入测试数据
INSERT INTO TABLE DB.JSON VALUES('{"id":"3","age":"12"}');
--5 使用临时函数getJsonObject()
SELECT getJsonObject(JSON_DATA,'id') as id, getJsonObject(JSON_DATA,'age') as age FROM DB.JSON WHERE pt_dt='2020-09-25';
输出:3 12
三、解析JSON数组的方法
(一)使用Hive自带的函数解析Json数组
说明:Hive的内置的explode函数,explode()函数接收一个 array或者map 类型的数据作为输入,然后将 array 或 map 里面的元素按照每行的形式输出。其可以配合 LATERAL VIEW 一起使用。
测试:
select explode(array('A','B','C'));
输出: A
B
C
select explode(map('A',10,'B',20,'C',30));
输出:A 10
B 20
C 30
这个explode函数和我们解析json数据是有关系的,我们可以使用explode函数将json数组里面的元素按照一行一行的形式输出:
SELECT explode(split(
regexp_replace(
regexp_replace(
'[
{"website":"www.baidu.com","name":"百度"},
{"website":"google.com","name":"谷歌"}
]',
'\\[|\\]',''), --将 Json 数组两边的中括号去掉
'\\}\\,\\{' --将 Json 数组元素之间的逗号换成分号
,'\\}\\;\\{'),
'\\;')); --以分号作为分隔符
输出:{"website":"www.baidu.com","name":"百度"}
{"website":"google.com","name":"谷歌"}
结合 get_json_object 或 json_tuple 来解析里面的字段:
select json_tuple(json, 'website', 'name') from (SELECT explode(split(regexp_replace(regexp_replace('[{"website":"www.baidu.com","name":"百},{"website":"google.com","name":"谷歌"}]', '\\[|\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')) as json) test;
输出:
www.baidu.com 百度
google.com 谷歌
(二)自定义函数解析JSON数组
虽然可以使用Hive自带的函数类解析Json数组,但是使用起来有些麻烦。Hive提供了强大的自定义函数(UDF)的接口,我们可以使用这个功能来编写解析JSON数组的UDF。
- 自定义函数
1.
2. package com.data;
3.
4. import org.apache.hadoop.hive.ql.exec.Description;
5. import org.apache.hadoop.hive.ql.exec.UDF;
6. import org.json.JSONArray;
7. import org.json.JSONException;
8. import java.util.ArrayList;
9.
10.
11. public class JsonArray extends UDF{
12. public ArrayList<String> evaluate(String jsonString) {
13. if (jsonString == null) {
14. return null;
15. }
16. try {
17. JSONArray extractObject = new JSONArray(jsonString);
18. ArrayList<String> result = new ArrayList<String>();
19. for (int ii = 0; ii < extractObject.length(); ++ii) {
20. result.add(extractObject.get(ii).toString());
21. }
22. return result;
23. } catch (JSONException e) {
24. return null;
25. } catch (NumberFormatException e) {
26. return null;
27. }
28. }
29.
30. }
将上面的代码进行编译打包,jar包名为:getJsonArrayUDF.jar
--1 将getJsonArrayUDF.jar上传到hdfs
source ${HADOOP_CLIENT}/bigdata_env
kinit -k etluser/hadoop -t ${WORK_ROOT}/etl_tools/config/etluser.keytab
hadoop fs -rm -f -r /user/etluser/pgm/tempUDF
hadoop fs -mkdir -f -r /user/etluser/pgm/tempUDF
hdsoop fs -put ${WORK_ROOT}/pgm/tempUDF/getJsonArrayUDF.jar /user/etluser/pgm/tempUDF/
--2 创建临时函数getJsonObject()
use udf;
set hive.security.temporary.function.need.admin=false;
create temporary function getJsonArray as 'com.data.JsonArray' using jar '/user/etluser/pgm/tempUDF/getJsonArrayUDF.jar';
--3 使用临时函数getJsonObject()
select explode(getJsonArray('[{"website":"www.baidu.com","name":"百度"},{"website":"google.com"name":"谷歌"}]'));
输出:www.baidu.com 百度
google.com 谷歌
四、对where条件的支持
(一)get_json_object(string json_string, string path)对where条件的支持
- 是否支持:是
- 实验
SELECT b.b_movie,b.b_rate,b.b_timeStamp,b.b_uid from db.json a
lateral view json_tuple(a.json_data, 'movie', 'rate', 'timeStamp', 'uid') b as b_movie,b_rate,b_timestamp,b_uid
where a.pt_dt='2020-09-25'
and get_json_object(a.json_data,'$.movie')='661';
(1) 输出:
661 3 9978302109 1
(2) 源表数据量:9条JSON格式数据,每条JSON数据又4个属性。
(3) 耗时:35.39s
(二)json_tuple(jsonStr, k1, k2, ...)对where条件的支持
- 是否支持:是
- 实验
SELECT b.b_movie,b.b_rate,b.b_timeStamp,b.b_uid from db.json a
lateral view json_tuple(a.json_data, 'movie', 'rate', 'timeStamp', 'uid') b as b_movie,b_rate,b_timestamp,b_uid
where a.pt_dt='2020-09-25'
and b.b_movie='661' and b.b_rate='3';
(1) 输出
661 3 978302109 1
(2) 源表数据量:9条JSON格式数据,每条JSON数据又4个属性。
(3) 耗时:42.422s
五、总结
在一些数据加工场景下,例如,当我们需要获取源表JSON字段中的相关信息时,就需要对该字段的JSON数据进行解析。这时候就十分需要Hive对JSON格式的数据解析提供支持。
目前Hive官方提供了get_json_object();json_tuple();explode();splite();regexp_replace()等函数,运用得当还是能解决不少问题。当然,这些函数的组合使用存在一定的限制性,编码风格也较为复杂,可读性较差;可以考虑使用自建UDF函数的方法,将JSON数据的解析放到Java等高级语言中去实现,简化解析JSON数据时的复杂编码,且能做到组件化复用。
Hive对JSON格式的支持研究的更多相关文章
- mysql 5.7 支持json格式
1.JSON格式的支持:mysql> create table user ( uid int auto_increment, -> data json,primary key(u ...
- ajax访问服务器返回json格式
使用ajax访问服务器返回多条数据,比如返回一个表中的所有数据,页面该如何处理呢?如何获取数据呢?一直不会用ajax返回json格式,今天研究了下,分享给大家~ 首先需要引用服务,点击项目右键,添加引 ...
- flash解析json格式
flash对于json格式的解析在Flash CS6的版本对于json格式的数据提供了支持,用以下方式即可以进行转换: var persons = JSON.parse('[{"name&q ...
- hive中导入json格式的数据(hive分区表)
hive中建立外部分区表,外部数据格式是json的如何导入呢? json格式的数据表不必含有分区字段,只需要在hdfs目录结构中体现出分区就可以了 This is all according to t ...
- MySQL 5.7原生JSON格式支持
在MySQL与PostgreSQL的对比中,PG的JSON格式支持优势总是不断被拿来比较.其实早先MariaDB也有对非结构化的数据进行存储的方案,称为dynamic column,但是方案是通过BL ...
- HIVE json格式数据的处理
今天要处理一个以json格式存储的数据,想要直接把json的各个项的数据存入HIVE表中. HIVE直接读入json的函数有两个: (1)get_json_object(string json_str ...
- 扩展SpringMVC以支持绑定JSON格式的请求参数
此方案是把请求参数(JSON字符串)绑定到java对象,,@RequestBody是绑定内容体到java对象的. 问题描述: <span style="font-size: x-sma ...
- 配置iis支持.json格式的文件
配置iis支持.json格式的文件发现要让IIS支持json文件并不是单纯的添加mime这么简单啊,以下是设置方法:一.IIS 6 1. MIME设置:在IIS的站点属性的HTTP头设置里,选MIME ...
- 配置IIS支持Json格式
配置iis支持.json格式的文件 原文地址:http://blog.eroad.info/iis-suport-json/ 在做easyUI的官方示例的时候 有的例子是直接读取的json文件,但是默 ...
- SpringBoot RestController 同时支持返回xml和json格式数据
@RestController 默认支持返回json格式数据,即使不做任何配置也能返回json数据 当接口需要支持xml或json两种格式数据时应该怎么做呢? 只要引入 Jackson xml的 ma ...
随机推荐
- 【 Python 】补全fibersim 导出的xml语法
fibersim导出的xml文件中,node 和mesh部分的标签会缺失.即<R></R>变成了<R/>. 以下python脚本可以自动修正 # ********* ...
- dig命令命令常见用法
域名结构 主机名.次级域名.域名.根域名 host. sld .tld .root 几种常见的解析类型 A记录 CNAME txt记录 dig命令命令常见用法 dig,"domain inf ...
- 多智能体粒子环境(Multi-Agent Particle Env)食用指南--从入门到入土
0.项目地址: 原地址:openai/multiagent-particle-envs: Code for a multi-agent particle environment used in the ...
- Vulnhub-Source-1(CVE-2019-15107)
一.靶机搭建 选择打开选项 选中下载的ova文件,然后导入选择一个存放路径即可 如果遇到不兼容的情况,可以打开.vmx修改,改为和虚拟机一个版本号 二.信息收集 官方信息 Name: Source: ...
- c++中的类成员函数指针
c++中的类成员函数指针 文章目录 c++中的类成员函数指针 发生的事情 正常的函数指针定义 定义类的成员函数指针 std::function 发生的事情 最近,想用一个QMap来创建字符串和一个函数 ...
- Qt QHeaderView 添加复选框
QT QTableView 表头添加复选框 最近在做表格,用QTableView,然后有一个需求是给表格添加表头,但是没有一个API能够在表头添加复选框,基本都是来重载QHeaderView,有两种方 ...
- vuepress-reco搭建与部署指南
个人博客:槿苏的知识铺 一.前言 在技术飞速发展的今天,高效地编写.维护和呈现文档已成为开发者不可或缺的能力.无论是开源项目.团队协作还是个人知识沉淀,一套结构清晰.体验优雅的文档系统都能显著提升 ...
- Golang 入门 : 字符串及底层字符类型
字符串 基本使用 在 Go 语言中,字符串是一种基本类型,默认是通过 UTF-8 编码的字符序列,当字符为 ASCII 码时则占用 1 个字节,其它字符根据需要占用 2-4 个字节,比如中文编码通常需 ...
- Linux reboot全过程
一.版本说明嵌入式Linux 下面的reboot命令看似简单,但出问题时定位起来发现别有洞天.下面就按在shell下执行reboot命令之后程序的执行过程进行解析.Busybox:1.23.2 ...
- CentOS 7 下 Docker 的离线安装方法
现遇到部分学校提供的服务器并没有外网连接,故需要在断网条件下安装 Docker ,本贴简述断网安装 Docker 的方法. 去 Docker 或者相关镜像源中下载 Docker RPM 包,以下链接的 ...