Hive處理Json數據
Json 格式的數據處理
Json 數據格式是我們比較常用的的一種數據格式,例如埋點數據、業務端的數據、前後端調用都採用的是這種數據格式,所以我們很有必要學習一下這種數據格式的處理方法
準備數據
cat json.data
{"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"}
創建hive表並且加載數據
create table ods.ods_json_data(text string);
load data local inpath "/Users/XXX/workspace/hive/json.data" overwrite into table ods.ods_json_data;
get_json_object 和 json_tuple 函數
json_tuple 不支持json 的嵌套處理,但是支持一次性獲取多個頂級的key對應的值
get_json_object 不支持一次獲取多個值,但是支持複雜json 的處理
get_json_object()
用法:get_json_object(string json_string, string path) 前面我們介紹過如何查看函數的用法desc function get_json_object
返回值:String
說明:解析json的字符串json_string,返回path指定的內容。如果輸入的json字符串無效,那麼返回NUll,這個函數每次只能返回一個數據項。
具體示例: get_json_object(value,』$.id』)
select get_json_object(text,"$.movie") from ods.ods_json_data;
這個函數的不足之處是,它只能返回一個值,就是我們不能一次性從json 中提取多個值,如果要提取多個值的話,就要多次調用這個函數,但是我們下面介紹的json_tuple 就可以,但是這不是說這個函數不強或者怎麼樣,記住這個函數的api 可以幫你節約很多時間
json_tuple
用法:json_tuple(jsonStr, p1, p2, …, pn) 整理的pn 就是我們要提取的鍵
返回值:tuple(v1,…vn) 這裡的返回值v1 … vn 和 鍵p1 …. pn 是相對應的
select json_tuple(text,'movie','rate','timeStamp','uid') from ods.ods_json_data;
json_tuple相當於get_json_object的優勢就是一次可以解析多個Json字段。
例子演示
1. 嵌套json 的處理
前面我們說了json_tuple不支持嵌套JSON 的處理
select get_json_object('{"movie":"594","rate":"4","timeStamp":"978302268","uid":"1","info":{"name":"天之驕子"}}',"$.info.name")
select json_tuple('{"movie":"594","rate":"4","timeStamp":"978302268","uid":"1","info":{"name":"天之驕子"}}',"info.name")
2. Json數組解析(get_json_object 實現)
SELECT get_json_object('[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]', '$.[0].website'), get_json_object('[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]', '$.[1].website');
這個時候時候你發現我提取的都是json 數組中的website
,有沒有什麼簡單的辦法呢,理論上get_json_object 只能有一個返回值,無論如何都需要寫多個,那你有沒有想過一個問題,我要是這個數組裏面有100個元素都是json,我需要每一個json 的website 那我是不是需要寫100次了,這個時候你要是仔細閱讀這個函數的api 的話,你就會發現了另外一個符號*
SELECT get_json_object('[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]', '$.[*].website')
這下你知道了,get_json_object 是只能返回一個元素,不是只能返回一個字符串,上面本來就是一個json 數組,那要是我們是從json 裏面解析出來的數組怎麼處理呢?
SELECT get_json_object('{"info":[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]}', '$.info');
需要注意下面這樣操作之後你拿到的就是一個json 字符串了,這下你就可以按照上面的方式再處理一次了
select get_json_object (get_json_object('{"info":[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]}', '$.info' ),'$.[1].website');
但是有時候我們希望直接獲取,而不是通過這樣嵌套的方式,這個時候其實就是將上面的嵌套的get_json_object函數的path 參數進行組合
SELECT get_json_object('{"info":[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]}', '$.info[1].website');
這個時候如果我們再上 * 進行加持,那就很簡單了
SELECT get_json_object('{"info":[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]}', '$.info[*].website');
其實到這裡我們學習了指定一個數組的某個下標獲取一個元素,指定* 獲取全部元素,那就如我就想獲取前三個或者偶數個或者奇數個呢,哈哈,如果你回過頭去看api 你就是知道了提供了一個Union operator
,指定任意你想組合的下標即可,獲取
SELECT get_json_object('{"info":[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"}]}', '$.info[0,1].website');
下面我們嘗試獲取一下偶數個,或者奇數個或者是一定範圍內的奇數個或者偶數個,其實就是上面提供的數組切片,你可以參考api 進行使用
SELECT get_json_object('{"info":[{"website":"www.ikeguang.com","name":"我的生活記憶"},{"website":"beian.ikeguang.com","name":"備案"},{"website":"www.ikeguang2.com","name":"我的生活記憶"}]}', '$.info[0:2:2].website');
但是我嘗試了一下,發現這個功能有bug,不能做到切片的效果,每次都是全部返回
SELECT get_json_object('{"info":[
{"website":"www.ikeguang.com","name":"我的生活記憶"},
{"website":"beian.ikeguang.com","name":"備案"},
{"website":"www.ikeguang2.com","name":"我的生活記憶"}]}', '$.info[0:2:2].website');
加載JSON 數據
對於上面json.data 的數據,我們能不能在load 數據到hive 的時候就處理,而不是load 完之後再到使用的時候去處理,尤其是針對這種嵌套結構不是很複雜的這種json 格式
create table ods.ods_json_parse_data(
movie string,
rate string,
`timeStamp` string,
uid string)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS TEXTFILE;
load data local inpath "/Users/liuwenqiang/workspace/hive/json.data" overwrite into table ods.ods_json_parse_data;
這種方法需要注意的是你的數據類型和字段名稱都要匹配,否則就會報錯或者不能獲取到值,那要是複雜一點的嵌套結構呢,其實也可以,在上面的數據基礎上添加了一個嵌套的字段也是可以的
{"movie":"1193","rate":"5","timeStamp":"978300760","uid":"1","info":{"name":"天之驕子"}}
create table ods.ods_json_parse_data2(
movie string,
rate string,
`timeStamp` string,
uid string,
info map<string,string>)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS TEXTFILE;
load data local inpath "/Users/liuwenqiang/workspace/hive/json.data" overwrite into table ods.ods_json_parse_data2;
總結
- get_json_object 和 json_tuple 函數的使用場景和其優缺點
- 如果json 格式比較簡單,那麼可以在建表加載數據的時候就可以將json 處理掉,如果比較複雜也可以再加載的時候解析一部分,然後再通過SQL 進行解析
- 也可以嘗試寫一些UDF 函數來處理JSON
關注公眾號:大數據技術派,回復”資料”,領取
1024G
資料。