前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高效JSON解析方案

高效JSON解析方案

原创
作者头像
一叶落知秋
发布2023-01-14 23:17:08
8060
发布2023-01-14 23:17:08
举报
文章被收录于专栏:数据之路数据之路

前言

JSON是常用的数据编码格式,在从海量JSON格式字符串数据中解析出所需值常常是计算的性能瓶颈,在大数据实时离线场景尤为常见。本文阐述一种高效解析JSON的方案和实现,相比较于jackson,在公司场景应用中,性能平均提升50%+。

基于JAVA的JSON处理源码参考github: https://github.com/lunar-ye/ProtoJson

参考测试用例:

代码语言:javascript
复制
// 用法JsonRowConverter构造方法为变长参数,传入要解析的多个路径
// 对下面例子,路径a返回:"1", 路径b.c返回 "xx", 路径b返回 {"c":"xx","d":[1,2,3],"e":[[1,2,3]]}
// 路径b.d返回[1,2,3],路径b.d.1返回2,路径b.e.0.0返回1
String json = "{\"a\":1,\"b\":{\"c\":\"xx\",\"d\":[1,2,3],\"e\":[[1,2,3]]}}";
JsonRowConverter converter = new JsonRowConverter("a","b","b.c", 'b.d.1');
String[] result = converter.process(json);
// 返回结果
// 1, {"c":"xx","d":[1,2,3],"e":[[1,2,3]]}, xx

基于该方案实现的HIVE JSON处理UDF源码:https://github.com/lunar-ye/ProtoJson/tree/kson_tuple

UDF用法参考:

代码语言:javascript
复制
-- kson_tuple用法类似于json_tuple,第一个参数为要解析的json字段,后面参数为要解析的多个路径
add jar viewfs://***.jar;
create temporary function kson_tuple as '***.video.KsonTuple';
select
  custom_key,
  custom_biz,
  custom_value,
  stat,
  stat_status, 
  err_msg,
  sdk_ver,
  max_retry_cnt
FROM
  table1 lateral view outer kson_tuple(
    custom_value,
    'stat',
    'stat.status',
    'stat.error_message',
    'sdk_ver',
    'config.max_retry_count'
  ) t as stat,stat_status, err_msg,sdk_ver,max_retry_cnt
where
  p_date = '{{ ds_nodash }}'AND p_hourmin = '{{hourmin}}'AND custom_key in ('VIDEO_IMAGE')

JACKSON瓶颈:

jackson是一种开源主流的json解析工具,详情可以参考:https://github.com/FasterXML/jackson

jackson常见有两种解析场景,一种为将json解析为JsonNode tree,另一种将json字符串解析为java类

代码语言:javascript
复制
ObjectMapper mapper = new ObjectMapper();
// 1. 解析成jsonnode tree
JsonNode node = mapper.readTree(json);
// 2. 解析成java对象
HashMap<String, String> map = (HashMap<String, String>) mapper.readValue(json, Map.class);

两种解析json的方法逻辑相似,可以分为下面几个部分。

首先,将json字符串进行词法解析,解析成JsonToken组合。

代码语言:javascript
复制
public JsonParser createParser(String content) throws IOException, JsonParseException {
    int strLen = content.length();
    if (this._inputDecorator == null && strLen <= 32768 && this.canUseCharArrays()) {
        IOContext ctxt = this._createContext(this._createContentReference(content), true);
        char[] buf = ctxt.allocTokenBuffer(strLen);
        content.getChars(0, strLen, buf, 0);
        return this._createParser(buf, 0, strLen, ctxt, true);
    } else {
        return this.createParser((Reader)(new StringReader(content)));
    }
}

然后,将调用DefaultSerializationContext的readRootValue方法。

代码语言:javascript
复制
public Object readRootValue(JsonParser p, JavaType valueType,
        JsonDeserializer<Object> deser, Object valueToUpdate)throws IOException
{
    if (_config.useRootWrapping()) {
        return _unwrapAndDeserialize(p, valueType, deser, valueToUpdate);
    }
    if (valueToUpdate == null) {
        return deser.deserialize(p, this);
    }
    return deser.deserialize(p, this, valueToUpdate);
}

最终会递归调用JsonDeserialize方法进解析JsonToken组合。

代码语言:javascript
复制
public abstract T deserialize(JsonParser p, DeserializationContext ctxt)throws IOException, JacksonException;

jackson定义了一系列json反序列化类,不同的反序列化类会将json反序列化为不同的类型。比如MapDeserializer类会将jsontoken集合解析为Map类型,而JsonNode deserializer类会将jsontoken集合解析为JsonNode类型。

但是jackson提供的官方解析方法为了保证易用性(把全量json构建成一棵树,用户按需取),存在会将大量的无用字段递归解析,并且会在json每个路径节点创建不同的对象。

比如:对于json字符串:"{\"a\":1,\"b\":{\"c\":\"xx\",\"d\":[1,2,3],\"e\":[[1,2,3]]}}"

哪怕我们只想解析"a"这个字段的值,当调用jackson的官方解析方法时候(比如readTree),也会将b、b.c、b.d等等字段全部解析出来,并且每个节点构造jsonnode的对象。

优化项:

针对jackson官方解析方案存在的两点问题,分别给出解决方案:

a. 无效字段解析:常见的数据清洗场景,用户需要的字段都是固定的,所以可以只解析需要的字段,不需要的字段可以快速跳过

b. 对象重复创建:将结果存储到节点树上,复用对象,不需要重复创建对象。

以示例JSON为例, a, b, b.c, b.d[1] 解析流程如下

代码语言:javascript
复制
{
	"a": 1,
	"b": {
		"c": "xx",
		"d": [1, 2, 3],
		"e": [
			[1, 2, 3]
		]
	}
}

a. 构造节点树,

b. 词法解析json字符串,生成JsonToken集合。

c. 深度遍历JsonToken,赋值节点树,返回结果。

构造了一个简单的case,测试快速json解析方案(protojson)和jackson通用的json解析方案性能。可以自行测试看看。

测试代码可以参考:https://github.com/lunar-ye/ProtoJson/blob/main/Demo/src/test/java/org/protojson/test/JsonRowConverterTest.java

2022-11-01 首发于快手技术博客

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JACKSON瓶颈:
  • 优化项:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档