在写Hive SQL时,需要从一个json列中解析出多个key的信息,查阅资料发现到有两种写法,一种是get_json_object,另外一种是json_tuple。两种用法的示例如下所示
get_json_object示例:
select get_json_object(json_str_column,'$.a1') as a1, get_json_object(json_str_column,'$.a2') as a2, get_json_object(json_str_column,'$.a3') as a3, from my_table;
json_tuple示例:
select B.a1, B.a2, B.a3 from my_table A lateral view json_tuple(json_str_column, 'a1', 'a2', 'a3') B as a1, a2, a3;
从写法上来说,json_tuple的写法SQL语句更少,更加的优雅,尤其当要解析出来的字段非常多时更加明显,但是json_tuple的性能如何呢?
再使用explain看下它们的执行计划:
两者的执行计划分别如下图所示:
get_json_object() 是个UDF,在Mapper阶段的列投影时完成获取解析json的操作,如果要获取多个key,那么json字段就要解析多次!
json_tuple() 这个函数在Hive里面是使用UDTF来实现的,即普通的一行转多行。它会生成两个Select Operator 操作,一个扫描不用解析的数据,生成一行,另外一个扫描需要解析的数据进行解析,然后再使用Lateral View Join Operator 操作将这两部分数据join关联起来。如下图所示:
LateralViewJoinOperator:
但是这里的Join并不是真正会触发Shuffle的join,只是讲非UDTF和UDTF字段通过ArrayList的addAll()连接在一起而已:
// acc is short for accumulator. It's used to build the row before forwarding ArrayList<Object> acc = new ArrayList<Object>(); // selectObjs hold the row from the select op, until receiving a row from // the udtf op ArrayList<Object> selectObjs = new ArrayList<Object>(); /** * An important assumption for processOp() is that for a given row from the * TS, the LVJ will first get the row from the left select operator, followed * by all the corresponding rows from the UDTF operator. And so on. */ @Override public void process(Object row, int tag) throws HiveException { StructObjectInspector soi = (StructObjectInspector) inputObjInspectors[tag]; if (tag == SELECT_TAG) { selectObjs.clear(); selectObjs.addAll(soi.getStructFieldsDataAsList(row)); } else if (tag == UDTF_TAG) { acc.clear(); // 这里就是所谓的join,只是连接再一起而已 acc.addAll(selectObjs); acc.addAll(soi.getStructFieldsDataAsList(row)); forward(acc, outputObjInspector); } else { throw new HiveException("Invalid tag"); } }
最后说下个人测试得出来的结论,感觉非常神奇,如果json字段并不是特别多(几十个Key),并且从json字段中解析的key并不是特别多时,json_tuple的性能要远低于get_json_object!
非常神奇...暂时还是不明白为啥json_tuple会慢,先记录下,后续慢慢分析好了...如果又知道的,麻烦和我说一下,感谢感谢!
参考:
https://www.cnblogs.com/BlueSkyyj/p/9720346.html(get_json_object使用方式)
https://www.cnblogs.com/zzhangyuhang/p/9791795.html(lateral view介绍)
https://zhuanlan.zhihu.com/p/137482744(LateralViewJoinOperator解析)
https://blog.csdn.net/lidongmeng0213/article/details/110877351(LateralViewJoinOperator解析)