直接上例子,下面是我要處理的 json 數據格式
{
"IP": "192.168.1.1",
"appName": "sichuan_yunyingyong",
"customEvent": [
{
"eventName": "xx1",
"du": "xx",
"timestamp": "1480521763049",
"eventParams": {
"ContentID": "yixiuge",
"account": "13856976635",
"networkType": "WIFI",
"result": "0",
"type": "11"
}
},
{
"eventName": "xx2",
"du": "xx",
"timestamp": "1480521763049",
"eventParams": {
"ContentID": "yixiuge",
"account": "13856976636",
"networkType": "WIFI",
"result": "0",
"type": "11"
}
}
]
}
這裏面有json對象,還有json array,json對象好解析,json array不好解析,接下來兩者都講解下,需要使用 lateral view
select
j1.j1_ip,
j1.j1_appName,
j2.j2_customEvent_json
FROM tab_json s
lateral view json_tuple(s.json, 'IP', 'appName', 'customEvent') j1 as j1_ip, j1_appName, j1_customEvent
lateral view posexplode(split(regexp_replace(regexp_replace(j1.j1_customEvent,'\\}\\,\\{','\\}\\|\\|\\{'),'\\[|\\]',''), '\\|\\|')) j2 as j2_customEvents_pos, j2_customEvent_json
這個表 tab_json是包含json數據的表,json是json數據的字段,結果爲
192.168.1.1 sichuan_yunyingyong {"eventName":"xx1","du":"xx","timestamp":"1480521763049","eventParams":{"ContentID":"yixiuge","account":"13856976635","networkType":"WIFI","result":"0","type":"11"}}
192.168.1.1 sichuan_yunyingyong {"eventName":"xx2","du":"xx","timestamp":"1480521763049","eventParams":{"ContentID":"yixiuge","account":"13856976636","networkType":"WIFI","result":"0","type":"11"}}
json數據就是直接把key當成字段,直接把key作爲json_tuple方法的參數即可,這種解析json對象比較簡單,如json_tuple(s.json, 'IP') 就是取json中字段IP的值,
但是,爲什麼原來是一條記錄怎麼解析成2條記錄了呢,問題如下
posexplode(split(regexp_replace(regexp_replace(j1.j1_customEvent,'\\}\\,\\{','\\}\\|\\|\\{'),'\\[|\\]',''), '\\|\\|')) j2 as j2_customEvents_pos, j2_customEvent_json
我把json array的格式通過替換變成了 {json1} || {json2} , 這種格式再根據 || 來拆開,形成了一個有兩個元素的數組
注意:hive轉義符需要寫兩個 \
接着 posexplode 在把數組變成(pos, json) 的鍵值對,pos記錄了元素的位置,json就是實際的json數據,這樣一條數據就變成了兩條了,這點要注意,數據量因爲這種操作,成倍的增加
解釋了這點,那麼我想獲取IP , appName , account 字段怎麼辦呢,我直接給出sql語句了
select
j1.j1_ip,
j1.j1_appName,
j4.j4_account
FROM tab_json s
lateral view json_tuple(s.json, 'IP', 'appName', 'customEvent') j1 as j1_ip, j1_appName, j1_customEvent
lateral view posexplode(split(regexp_replace(regexp_replace(j1.j1_customEvent,'\\}\\,\\{','\\}\\|\\|\\{'),'\\[|\\]',''), '\\|\\|')) j2 as j2_customEvents_pos, j2_customEvent_json
lateral view json_tuple(j2.j2_customEvent_json, 'eventParams') j3 as j3_eventParams
lateral view json_tuple(j3.j3_eventParams, 'account') j4 as j4_account
結果如下:
192.168.1.1 sichuan_yunyingyong 13856976635
192.168.1.1 sichuan_yunyingyong 13856976636
上面的例子json array有兩個元素,如果你只關注其中一個元素,那麼可以如下操作
lateral view posexplode(array(split(regexp_replace(regexp_replace(j1.j1_customEvent,'\\}\\,\\{','\\}\\|\\|\\{'),'\\[|\\]',''), '\\|\\|')[1])) j2 as j2_customEvents_pos, j2_customEvent_json
split 跟上數組下標,就能取出某個元素,由於posexplode只接受 array類型的參數,可以使用array函數轉換成對應的數組,這樣就只有一條數據了,結果如下
192.168.1.1 sichuan_yunyingyong 13856976636
總結下:
在現在的hive版本中,hive 2還沒有試用,不知道是不是已經引入了json array的解析函數了,目前的版本是不能通過方法解析的,
思路是,通過給json array替換字符,由原來的 [ {} , {} ] 變成 {} || {} 這樣,在轉換成數組用 posexplode 函數,這樣就可以了
當然實際使用時數據放大也要注意,如果json array只有一個元素就不會放大
在只有一個元素的情況下,直接把 [ ] 去掉,用array 轉成數組即可
以後可以自己寫一個UDF來解析json array,欲知詳情,請聽下回分解