Hive sql 解析Json數(shù)組

我們都知道,Hive內(nèi)部提供了大量的內(nèi)置函數(shù)用于處理各種類型的需求,參見官方文檔:Hive Operators and User-Defined Functions (UDFs)。我們從這些內(nèi)置的 UDF 可以看到兩個用于解析 Json 的函數(shù):get_json_object和json_tuple。用過這兩個函數(shù)的同學肯定知道,其職能解析最普通的 Json 字符串,如下:

hive (default)>? SELECT?get_json_object('{"website":"www.iteblog.com","name":"過往記憶"}', '$.website');

OK

www.iteblog.com


hive (default)> SELECT?json_tuple('{"website":"www.iteblog.com","name":"過往記憶"}', 'website', 'name');

OK

www.iteblog.com 過往記憶

Time?taken: 0.074 seconds, Fetched: 1 row(s)

json_tuple相對于get_json_object的優(yōu)勢就是一次可以解析多個 Json 字段。但是如果我們有個 Json 數(shù)組,這兩個函數(shù)都無法處理,get_json_object處理 Json 數(shù)組的功能很有限,如下:

hive (default)>

????????????????>

????????????????> SELECT?get_json_object('[{"website":"www.iteblog.com","name":"過往記憶"}, {"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}]', '$.[0].website');

OK

www.iteblog.com

Time?taken: 0.069 seconds, Fetched: 1 row(s)

注意spark不支持,和hive的區(qū)別在于$后面有沒有.

select?

get_json_object(get_json_object(repair_content,'$.repairUseMac'),'$[0].count')

from

info.ods_xmsfactory_t_srv_factory_repair

where?id='XZ2007023300233'

如果我們想將整個 Json 數(shù)組里面的 website 字段都解析出來,如果這么寫將非常麻煩,因為我們無法確定數(shù)組的長度,而且即使確定了,這么寫可維護性也很差,所以我們需要想別的辦法。

如果想及時了解Spark、Hadoop或者Hbase相關(guān)的文章,歡迎關(guān)注微信公共帳號:iteblog_hadoop

使用Hive自帶的函數(shù)解析 Json 數(shù)組

在介紹如何處理之前,我們先來了解下Hive內(nèi)置的explode函數(shù),官方的解釋是:explode() takes in an array (or a map) as an input and outputs the elements of the array (map) as separate rows. UDTFs can be used in the SELECT expression list and as a part of LATERAL VIEW.意思就是explode()接收一個 array 或 map 類型的數(shù)據(jù)作為輸入,然后將 array 或 map 里面的元素按照每行的形式輸出。其可以配合LATERAL VIEW一起使用。光看文字描述很不直觀,咱們來看看幾個例子吧。

hive (default)> select?explode(array('A','B','C'));

OK

A

B

C

Time?taken: 4.188 seconds, Fetched: 3 row(s)


hive (default)> select?explode(map('A',10,'B',20,'C',30));

OK

A 10

B 20

C 30

相信不需要我描述大家就能看明白這個函數(shù)的意義。大家可能會問,這個函數(shù)和我們解析 Json 數(shù)組有毛關(guān)系啊。其實有關(guān)系,我們其實可以使用這個函數(shù)將 Json 數(shù)組里面的元素按照一行一行的形式輸出。根據(jù)這些已有的知識,我們可以寫出以下的 SQL 語句:

hive (default)> SELECT?explode(split(regexp_replace(regexp_replace('[{"website":"www.iteblog.com","name":"過往記憶"},{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}]', '{','\\}\\;\\{'),'\\[|\\]',''),'\\;'));

OK

{"website":"www.iteblog.com","name":"過往記憶"}

{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}

現(xiàn)在我們已經(jīng)能正確的解析 Json 數(shù)據(jù)了。

你現(xiàn)在肯定不知道上面一堆的 SQL 是啥含義,這里我來一步一步的解釋。


explode函數(shù)只能接收數(shù)組或 map 類型的數(shù)據(jù),而split函數(shù)生成的結(jié)果就是數(shù)組;

第一個regexp_replace的作用是將 Json 數(shù)組元素之間的逗號換成分號,所以使用完這個函數(shù)之后,[{"website":"www.iteblog.com","name":"過往記憶"},{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}]會變成[{"website":"www.iteblog.com","name":"過往記憶"};{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}]

第二個regexp_replace的作用是將 Json 數(shù)組兩邊的中括號去掉,所以使用完這個函數(shù)之后,[{"website":"www.iteblog.com","name":"過往記憶"},{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}]會變成{"website":"www.iteblog.com","name":"過往記憶"},{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}

然后我們可以結(jié)合get_json_object或json_tuple來解析里面的字段了:

hive (default)> select?json_tuple(json, 'website', 'name') from?(SELECT?explode(split(regexp_replace(regexp_replace('[{"website":"www.iteblog.com","name":"過往記憶"},{"website":"carbondateblog.com","name":"carbondata 中文文檔"}]', '\\}\\,\\{','\\}\\;\\{'),'\\[|\\]',''),'\\;')) as?json) iteblog;

OK

www.iteblog.com 過往記憶

carbondata.iteblog.com? carbondata 中文文檔

Time?taken: 0.189 seconds, Fetched: 2 row(s)

自定義函數(shù)解析 Json 數(shù)組

雖然可以使用 Hive 自帶的函數(shù)類解析 Json 數(shù)組,但是使用起來還是有些麻煩。值得高興的是, Hive 提供了強大的自定義函數(shù)(UDF)的接口,我們可以使用這個功能來編寫解析 Json 數(shù)組的 UDF。具體的代碼如下:

package?com.iteblog.udf.json;


import?org.apache.hadoop.hive.ql.exec.Description;

import?org.apache.hadoop.hive.ql.exec.UDF;

import?org.json.JSONArray;

import?org.json.JSONException;


import?java.util.ArrayList;



@Description(name = "json_array",

????????value = "_FUNC_(array_string) - Convert a string of a JSON-encoded array to a Hive array of strings.")

public?class?UDFJsonAsArray extends?UDF {

????public?ArrayList<String> evaluate(String jsonString) {

????????if?(jsonString == null) {

????????????return?null;

????????}

????????try?{

????????????JSONArray extractObject = new?JSONArray(jsonString);

????????????ArrayList<String> result = new?ArrayList<String>();

????????????for?(int?ii = 0; ii < extractObject.length(); ++ii) {

????????????????result.add(extractObject.get(ii).toString());

????????????}

????????????return?result;

????????} catch?(JSONException e) {

????????????return?null;

????????} catch?(NumberFormatException e) {

????????????return?null;

????????}

????}

}

上面的代碼邏輯很簡單,我就不介紹了。將上面的代碼進行編譯打包,假設(shè)打包完的 jar 包名稱為 iteblog.jar,然后我們就可以如下使用這個函數(shù)了。

hive (default)> add?jar /home/iteblog/iteblog.jar;

Added [/home/iteblog/iteblog.jar] to?class path

Added resources: [/home/iteblog/iteblog.jar]

hive (default)> create?temporary?function?json_array as?'com.iteblog.udf.json.UDFJsonAsArray';

OK

Time?taken: 0.013 seconds

hive (default)>

??????????????> select?explode(json_array('[{"website":"www.iteblog.com","name":"過往記憶"},{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}]'));

OK

{"website":"www.iteblog.com","name":"過往記憶"}

{"website":"carbondata.iteblog.com","name":"carbondata 中文文檔"}

Time?taken: 0.08 seconds, Fetched: 2 row(s)


hive (default)> select?json_tuple(json, 'website', 'name') from?(SELECT?explode(json_array('[{"website":"www.iteblog.com","name":"過往記憶"},{"website":"carbondata.iteblog.com","name":"carbta 中文文檔"}]')) as?json) iteblog;

OK

www.iteblog.com 過往記憶

carbondata.iteblog.com? carbondata 中文文檔

Time?taken: 0.082 seconds, Fetched: 2 row(s)

這個結(jié)果和上面使用 Hive 內(nèi)置的函數(shù)結(jié)果一致。當然,你還可以實現(xiàn)其他的 UDF,邏輯和這個類似,就不再介紹了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Hive中Map類型的操作 map的結(jié)構(gòu) 創(chuàng)建map的表create table temp_db.map_test...
    別停下思考閱讀 43,486評論 3 8
  • 在使用Hive搭建數(shù)據(jù)倉庫,處理數(shù)據(jù)時,同傳統(tǒng)數(shù)倉的結(jié)構(gòu)化數(shù)據(jù)不同,我們經(jīng)常會遇到一些非結(jié)構(gòu)化的數(shù)據(jù),json格式...
    風箏flying閱讀 11,229評論 0 1
  • 關(guān)系運算 1、等值比較: = 語法:A=B操作類型:所有基本類型描述: 如果表達式A與表達式B相等,則為TRUE;...
    phylicia2018閱讀 506評論 0 0
  • 文章目錄 1 關(guān)系運算1.1 1、等值比較: =1.2 2、不等值比較:1.3 3、小于比較:1.4 4、小于等于...
    叫我老村長閱讀 949評論 0 2
  • [toc] 關(guān)系運算 1、等值比較: = 語法:A=B操作類型:所有基本類型描述: 如果表達式A與表達式B相等,則...
    三分清醒閱讀 599評論 0 0

友情鏈接更多精彩內(nèi)容