hive解析不確定key的json,將key和value分別放入兩列

最近接到需求:客戶端上報json數據,入數據庫後需要對json中的key分組統計時長和次數,但json中的key是不確定的,經常會增刪。

明細層模型設計:將key和value分別設計爲1列,這樣能不需要關心json中的key和value怎麼變,都就根據客戶端上報的數據放入數據數據庫
由此引發思索:

  1. 在json不確定的key和value情況下,怎麼把key和value取出,並進行行轉列放入表中?
  2. hive自帶解析json的的函數get_json_object和json_tuple都必須要指定key才能將json解析出,並且一個key一列,value作爲key列中的值

最開始的想法是通過自定義函數實現該功能,但自定義函數有時並不是很穩定
Java實現解析json中key和value

package com.fuyun.java;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import java.util.Iterator;

/**
 * @Author: 浮雲
 * @Date: 2020/1/8 18:09
 */
public class ParseJsonTest {
    public static void main(String[] args) {
        String jsonData = "{\"name\":\"Bob\",\"age\":\"18\"}";
        try {
            JSONObject jsonObject = new JSONObject(jsonData);
            //通過迭代器獲取這段json當中所有的key值
            Iterator keys = jsonObject.keys();
            //然後通過一個循環取出所有的key值
            while (keys.hasNext()){
                String key = String.valueOf(keys.next());
                //最後就可以通過剛剛得到的key值去解析後面的json了
                String value = jsonObject.optString(key);
                System.out.println("key:" + key + "  value:" + value);
            }
        } catch (JSONException je) {
            je.printStackTrace();
        }
    }
}

以下用hive自帶函數實現該功能
表中的數據大概爲這樣:

operation_name  network_type    detail_load_time    load_time
電信	WIFI	NULL    231
電信	NONETWORK	{"MonkeySdkTime":173,"shellTime":100,"shellTime2":36,"ProbeSDKTime":88,"playerSDKTime":674,"pushSDKTime":34}    398
  1. 將json中所有key和value解析出來轉換爲數組
select operation_name
      ,network_type
      ,arr1_detail_load_time
      ,load_time
  from temp.temp_page_detail_load_time
--去掉兩表的{}再按,分割成數組,再行轉列
lateral view explode(split(regexp_replace(detail_load_time, '\\{|\\}', ''), ',')) arr1 as arr1_detail_load_time 
 limit 2;

result:
移動	WIFI	"shellTime":167	3211
移動	WIFI	"shellTime2":30	3211

這樣存在一個小小的bug:會過濾detail_load_time爲null的數據,優化代碼:

select operation_name
      ,network_type
      ,arr1_detail_load_time
  from temp.temp_page_detail_load_time
--先將null值做轉換,再去掉兩表的{}再按,分割成數組,再行轉列
lateral view explode(split(regexp_replace(nvl(detail_load_time, '-998'), '\\{|\\}', ''), ',')) arr1 as arr1_detail_load_time
 limit 2;

result:
移動	WIFI	"ProbeSDKTime":198	3221
移動	WIFI	"playerSDKTime":36	3221
  1. 將上面準換好的數組再進行分割,分別解析出key和value置爲兩列
select operation_name
      ,network_type
      --先將"去掉,再按:分割成數組
      ,split(regexp_replace(arr1.arr1_detail_load_time, '"', ''), ':')[0] detail_load_time_type 
      ,cast(nvl(split(regexp_replace(arr1.arr1_detail_load_time, '"', ''), ':')[1], 0) as bigint) detail_load_time
  from temp.temp_page_detail_load_time
--去掉兩表的{}再按,分割成數組,再行轉列
lateral view explode(split(regexp_replace(nvl(detail_load_time, '-998'), '\\{|\\}', ''), ',')) arr1 as arr1_detail_load_time 
 limit 2;

reslut:
電信	WIFI	-998	0
移動	WIFI	playerSDKTime	167

這樣就大功告成!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章