超久超久沒寫博客了,近來的都是比較雜的臨時活,大家都在喊他的活很急,最要緊,挺令我心煩的,不過有活總比沒活做好吧!
言歸正傳,本文講的是hive解析json格式的數據
最近處理了這麼一份數據,json格式的,其實我之前寫了一篇博客:
hive加載json數據和解析json(一):https://blog.csdn.net/lsr40/article/details/79399166
前言:
上一篇博客雖說介紹了兩種手段處理json
方法一:通過Serde直接加載json
方法二:通過hive內置的函數從字符串總提取json中的value
不過還是相對着重的介紹了get_json_object()和json_tuple()這兩個內置函數,對Serde的使用只是一筆帶過,這次我在做json加載的時候採用了第一種方式(serde加載json)
數據格式如下:
{
"key1": "xxxx",
"key2": "XXXX",
"map1": {
"M-a": "ma",
"M-b": "mb",
"M-c": "mc"
},
"last": "last1"
}
提出問題:
解釋下看到數據後我的想法:
1、是否需要額外添加jar包,如何添加?
2、其他的數據都是string類型,map1字段需要是Map或者Struts類型
3、map1中,M-a,M-b,這種不規整的字段名稱,是否可以映射成其他名稱,比如變成m_a,m_b這樣
4、json數據中沒有日期的字段,需要自己生成一個日期字段。
解決方法:
問題1的解決:
1、需要添加額外JsonSerde的jar包,可以使用apache有自帶的JsonSerde(上一篇文章中有說),也可以使用另一個功能更加強大的JsonSerde(如果json格式比較複雜,推薦使用後者)
http://www.congiu.net/hive-json-serde/1.3.7/cdh5/json-serde-1.3.7-jar-with-dependencies.jar
2、要添加兩個地方
第一:本地的hive客戶端
在客戶端的hive的lib裏面添加,讓hive啓動的時候能夠直接加載,或者每次手動執行add jar命令
第二:向集羣添加這個jar,放到$HADOOP_HOME/share/hadoop/mapreduce/對應的路徑下
可以參考:http://www.voidcn.com/article/p-dewklslz-bhu.html
必須兩步都做好,否則會有各種各樣的類找不到的報錯
例如:
Task with the most failures(4):
-----
Task ID:
task_1559639870610_13878_m_000000
URL:
http://master節點:8088/taskdetails.jsp?jobid=job_1559639870610_13878&tipid=task_1559639870610_13878_m_000000
-----
Diagnostic Messages for this Task:
Error: java.lang.RuntimeException: Error in configuring object
at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:109)
at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:75)
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:133)
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:455)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:343)
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:164)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1924)
at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:158)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:106)
... 9 more
Caused by: java.lang.RuntimeException: Error in configuring object
at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:109)
at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:75)
at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:133)
at org.apache.hadoop.mapred.MapRunner.configure(MapRunner.java:38)
... 14 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:106)
... 17 more
Caused by: java.lang.RuntimeException: Map operator initialization failed
at org.apache.hadoop.hive.ql.exec.mr.ExecMapper.configure(ExecMapper.java:147)
... 22 more
Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.ClassNotFoundException: Class org.openx.data.jsonserde.JsonSerDe not found
at org.apache.hadoop.hive.ql.exec.MapOperator.getConvertedOI(MapOperator.java:323)
at org.apache.hadoop.hive.ql.exec.MapOperator.setChildren(MapOperator.java:333)
at org.apache.hadoop.hive.ql.exec.mr.ExecMapper.configure(ExecMapper.java:116)
... 22 more
Caused by: java.lang.ClassNotFoundException: Class org.openx.data.jsonserde.JsonSerDe not found
at org.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:2255)
at org.apache.hadoop.hive.ql.plan.PartitionDesc.getDeserializer(PartitionDesc.java:137)
at org.apache.hadoop.hive.ql.exec.MapOperator.getConvertedOI(MapOperator.java:297)
... 24 more
問題2,3的解決:
問題3只有用推薦的jar包才能解決!
創建表如下:
--先添加剛剛下載到的jar包,然後再創建表
add jar /opt/json-serde-1.3.7-jar-with-dependencies.jar;
create table json_test(
`key1` string,
`key2` string,
`map1` struct
<
`m_a`:string,
`m_b`:string,
`m_c`:string> ,
`last` string)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
with serdeproperties
(
"mapping.m_a" = "M-a",
"mapping.m_b" = "M-b",
"mapping.m_c" = "M-c"
)
STORED AS TEXTFILE;
--其實map1那個字段大家也可以創建成Map<String,String>使用的時候和Strunct有所區別
--一個是map1[m_a],一個是map1.m_a
問題4的解決:
問題4是一個很麻煩的問題!
我是這麼做的,新增了一個pt_days的日期分區字段
add jar /opt/json-serde-1.3.7-jar-with-dependencies.jar;
create table json_test(
`key1` string,
`key2` string,
`map1` struct
<
`m_a`:string,
`m_b`:string,
`m_c`:string> ,
`last` string)
PARTITIONED BY (
`pt_days` string)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
with serdeproperties
(
"mapping.m_a" = "M-a",
"mapping.m_b" = "M-b",
"mapping.m_c" = "M-c"
)
STORED AS TEXTFILE;
當我如上建表之後
我執行: load data local inpath 'json文件塊' into json_test partition (pt_days=20191001);
加載數據正常,但是查詢數據的時候直接報空指針的錯:
Failed with exception nulljava.lang.NullPointerException
我估計是Serde解析json數據的時候,找不到pt_days字段,所以報錯了,因爲需求比較急,我也沒有太多的時候認真研究如何解決這個報錯,因此我取了一個折中的方法。
創建一張格式爲orc的有分區的最終表,然後爲每一天數據創建一張臨時表(表名爲:xxxx_數據日期),把當天的數據錄到各自的臨時表中,錄完之後,把該臨時表的數據往最終表裏去導入(導入完成刪除臨時表),這時候添加上時間的字段,而且因爲數據格式變爲orc,既可以節省空間,又可以加快查詢!
如果大家有更好的方法,歡迎留言~
好,菜雞一隻,幹活去了溜了溜了!
apache的json解析類和我推薦的那個json解析類具體有什麼區別,大家可以百度下,或者看如下的文章:
0659-6.2.0-Hive處理JSON格式數據:https://cloud.tencent.com/developer/article/1451308(作者:Fayson)