Hive 處理json數據總體來說有三個辦法:
-
使用內建的函數get_json_object、json_tuple
-
使用自定義的UDF(一進一出),自定義UDTF(一進多出)
-
第三方的SerDe--》JSONSerder
1、使用內建函數處理
get_json_object(string json_string, string path)
返回值:String
說明:解析json字符串json_string,返回path指定的內容;如果輸入的json字符串無效,那么返回NUll;函數每次只能返回一個數據項;
json_tuple(jsonStr, k1, k2, ...)
返回值:所有的輸入參數、輸出參數都是String;
說明:參數為一組鍵k1,k2,。。。。。和json字符串,返回值的元組。該方法比get_json_object高效,因此可以在一次調用中輸入多個鍵;
explode,使用explod將Hive一行中復雜的 array 或 map 結構拆分成多行。
測試數據:
user1;18;male;{"id": 1,"ids": [101,102,103],"total_number": 3}
user2;20;female;{"id": 2,"ids": [201,202,203,204],"total_number": 4}
user3;23;male;{"id": 3,"ids": [301,302,303,304,305],"total_number": 5}
user4;17;male;{"id": 4,"ids": [401,402,403,304],"total_number": 5}
user5;35;female;{"id": 5,"ids": [501,502,503],"total_number": 3}
建表加載數據:
CREATE TABLE IF NOT EXISTS jsont1(
username string,
age int,
sex string,
json string
)
row format delimited fields terminated by ';';
load data local inpath '/root/data/weibo.json' overwrite into table jsont1;
json的處理:
-- get 單層值
select username, age, sex, get_json_object(json, "$.id") id,
get_json_object(json, "$.ids") ids,
get_json_object(json, "$.total_number") num
from jsont1;
-- get 數組
select username, age, sex, get_json_object(json, "$.id") id,
get_json_object(json, "$.ids[0]") ids0,
get_json_object(json, "$.ids[1]") ids1,
get_json_object(json, "$.ids[2]") ids2,
get_json_object(json, "$.ids[3]") ids3,
get_json_object(json, "$.total_number") num
from jsont1;
-- 使用 json_tuple 一次處理多個字段
select json_tuple(json, 'id', 'ids', 'total_number')
from jsont1;
-- 有語法錯誤
select username, age, sex, json_tuple(json, 'id', 'ids', 'total_number')
from jsont1;
-- 使用 explode + lateral view
-- 在上一步的基礎上,再將數據展開
-- 第一步,將 [101,102,103] 中的 [ ] 替換掉
-- select "[101,102,103]"
-- select "101,102,103"
select regexp_replace("[101,102,103]", "\\[|\\]", "");
-- 第二步,將上一步的字符串變為數組
select split(regexp_replace("[101,102,103]", "\\[|\\]", ""), ",");
-- 第三步,使用explode + lateral view 將數據展開
select username, age, sex, id, ids, num
from jsont1
lateral view json_tuple(json, 'id', 'ids', 'total_number') t1 as id, ids, num;
with tmp as(
select username, age, sex, id, ids, num
from jsont1
lateral view json_tuple(json, 'id', 'ids', 'total_number') t1 as id, ids, num
)
select username, age, sex, id, ids1, num
from tmp
lateral view explode(split(regexp_replace(ids, "\\[|\\]", ""), ",")) t1 as ids1;
小結:json_tuple 優點是一次可以解析多個json字段,對嵌套結果的解析操作復雜;
2、使用UDF處理
自定義UDF處理json串中的數組。自定義UDF函數:
-
輸入:json串、數組的key
-
輸出:字符串數組
pom文件
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>2.3.7</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.23</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
package cn.lagou.dw.hive.udf;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.junit.Test;
import java.util.ArrayList;
public class ParseJsonArray extends UDF {
public ArrayList<String> evaluate(String jsonStr, String arrKey){
if (Strings.isNullOrEmpty(jsonStr)) {
return null;
}
try{
JSONObject object = JSON.parseObject(jsonStr);
JSONArray jsonArray = object.getJSONArray(arrKey);
ArrayList<String> result = new ArrayList<>();
for (Object o: jsonArray){
result.add(o.toString());
}
return result;
} catch (JSONException e){
return null;
}
}
使用自定義 UDF 函數:
-- 添加開發的jar包(在Hive命令行中)
add jar /root/edu_jars/my_udf.jar;
-- 創建臨時函數。指定類名一定要完整的路徑,即包名加類名
create temporary function lagou_json_array as "com.lagou.edu.ParseJsonArray";
-- 執行查詢
-- 解析json串中的數組
select username, age, sex, lagou_json_array(json, "ids") ids
from jsont1;
-- 解析json串中的數組,並展開
select username, age, sex, ids1
from jsont1
lateral view explode(lagou_json_array(json, "ids")) t1 as ids1;
-- 解析json串中的id、num
select username, age, sex, id, num
from jsont1
lateral view json_tuple(json, 'id', 'total_number') t1 as id, num;
-- 解析json串中的數組,並展開
select username, age, sex, ids1, id, num
from jsont1
lateral view explode(lagou_json_array(json, "ids")) t1 as ids1
lateral view json_tuple(json, 'id', 'total_number') t1 as id, num;
3、 使用UDTF處理
UDTF返回結果如下:
id | ids | total_number |
---|---|---|
1 | 101 | 3 |
1 | 102 | 3 |
1 | 103 | 3 |
package com.lagou.edu.udtf;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.List;
/**
* 官網編寫UDTF地址:https://cwiki.apache.org/confluence/display/Hive/DeveloperGuide+UDTF
*/
public class ParseJsonArrayUDTF extends GenericUDTF {
private String[] obj = new String[3];
/**
* 輸出字段名稱及數據類型
* @param argOIs
* @return
* @throws UDFArgumentException
*/