spark 異常:ClassCastException: Text cannot be cast to org.apache.hadoop.hive.ql.io.orc.OrcSerde$OrcSerdeRow


最近在執行Hive insert/select語句的過程碰到下面這種類型的異常:

異常1:

Caused by: java.lang.ClassCastException: org.apache.hadoop.io.Text cannot be cast to org.apache.hadoop.hive.ql.io.orc.OrcSerde$OrcSerdeRow
at org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat$OrcRecordWriter.write(OrcOutputFormat.java:81)
at org.apache.hadoop.hive.ql.exec.FileSinkOperator.process(FileSinkOperator.java:753)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:837)
at org.apache.hadoop.hive.ql.exec.LimitOperator.process(LimitOperator.java:54)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:837)
at org.apache.hadoop.hive.ql.exec.SelectOperator.process(SelectOperator.java:88)
at org.apache.hadoop.hive.ql.exec.mr.ExecReducer.reduce(ExecReducer.java:235)
... 7 more

異常2:

Failed with exception java.io.IOException:java.lang.ClassCastException: org.apache.hadoop.hive.ql.io.orc.OrcStruct cannot be cast to org.apache.hadoop.io.BinaryComparable
本文已上述的錯誤為切入點,分析下異常原因以及Hive相關的關於Format的異常。主要內容如下:

  1. 異常的原因分析及解決方法
  2. FAQ
  3. 異常的原因分析及解決方法
    1.1 異常1分析

異常1:

Caused by: java.lang.ClassCastException: org.apache.hadoop.io.Text cannot be cast to org.apache.hadoop.hive.ql.io.orc.OrcSerde$OrcSerdeRow
at org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat$OrcRecordWriter.write(OrcOutputFormat.java:81)
at org.apache.hadoop.hive.ql.exec.FileSinkOperator.process(FileSinkOperator.java:753)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:837)
at org.apache.hadoop.hive.ql.exec.LimitOperator.process(LimitOperator.java:54)
at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:837)
at org.apache.hadoop.hive.ql.exec.SelectOperator.process(SelectOperator.java:88)
at org.apache.hadoop.hive.ql.exec.mr.ExecReducer.reduce(ExecReducer.java:235)
... 7 more
該異常發生在insert overwrite階段,即select出來的數據插入目標表時拋出異常。從異常棧中可以清楚地看到OrcOutputFormat、java.lang.ClassCastException這些信息,可見這是Reduce任務將最終結果進行持久化(寫入HDFS文件系統)時出現錯誤。首先,我們需要明確這個數據持久化的大體流程是什么樣的?如下圖所示:

read-process
Read過程:InputFormat將輸入流(InputStream)分割成紀錄(<key,value>),Deserializer將紀錄(<key,value>)解析成列對象。

write-process
Write過程:Serializer將列對象轉化為紀錄(<key,value>),OutputFormat將紀錄(<key,value>)格式化為輸出流(OutputStream)。

上圖中描繪的分別是數據載入內存和持久化的過程。異常信息中的OrcOutputFormat說明錯誤出在數據持久化過程中。從圖中可知,序列化器Serializer的輸出數據,就是OutputFormat的輸入數據。接下來就是確定目標表的SerDe/InputFormat/OutputFormat分別是什么。通過下面命令查看。

desc formatted $table

結果如下:

desc formatted $table

Storage Information

SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
InputFormat: org.apache.hadoop.hive.ql.io.orc.OrcInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat
由上可知,目標表的SerDe為LazySimpleSerDe,而其Input/OutputFormat是orc的。所以異常1的原因也就得出:

異常1原因:序列化/反序列化器LazySimpleSerDe在執行serialize后的結果類型是Text,而OrcOutputFormat的接收數據類型必須是OrcSerdeRow。這就造成了ClassCastException。

下面是OrcOutputFormat的write方法源碼:

public class OrcOutputFormat extends ... {

@Override
public void write(Writable row) throws IOException {
  // 若類型不匹配,會拋出異常。
  OrcSerdeRow serdeRow = (OrcSerdeRow) row;
  if (writer == null) {
    options.inspector(serdeRow.getInspector());
    writer = OrcFile.createWriter(path, options);
  }
  writer.addRow(serdeRow.getRow());
}
。。。

}
原因找到后,解決辦法就很簡單了,將該table的fileformat修改為orc即可,如下所示:

ALTER TABLE $table SET FILEFORMAT ORC;
1.2 異常2分析

異常2:

Failed with exception java.io.IOException:java.lang.ClassCastException: org.apache.hadoop.hive.ql.io.orc.OrcStruct cannot be cast to org.apache.hadoop.io.BinaryComparable
通過異常1的分析后,這個異常的原因也就很容易定位了,數據讀取階段:OrcInputFormat的輸出結果是OrcStruct類型,其作為輸入數據傳給LazySimpleSerDe的deserialize方法,很明顯,deserialize中進行類型轉換時拋出該異常。下面是LazySimpleSerDe的doDeserialize方法源碼:

@Override
public Object doDeserialize(Writable field) throws SerDeException {
if (byteArrayRef == null) {
byteArrayRef = new ByteArrayRef();
}
// OrcStruct -> BinaryComparable
BinaryComparable b = (BinaryComparable) field;
byteArrayRef.setData(b.getBytes());
cachedLazyStruct.init(byteArrayRef, 0, b.getLength());
lastOperationSerialize = false;
lastOperationDeserialize = true;
return cachedLazyStruct;
}
下圖是已TEXTFILE格式作為存儲格式時的讀取流程:

textfile-read-process

現在將TextInputFormat換成OrcInputFormat后:

orc-text-incompatible
小結:以上兩種異常的根本原因都是由於序列化/反序列化器SerDe和InputFormat/OutputFormat不匹配造成的。這通常是由於創建表時沒有正確指定這三個配置項造成的。

FAQ

  1. stored as orc 和 stored as INPUTFORMAT ... OUTPUTFORMAT ...的區別?
    當我們使用stored as orc的時候,其實已經隱式的指定了下面三個配置:

SERDE:org.apache.hadoop.hive.ql.io.orc.OrcSerde
INPUTFORMAT:org.apache.hadoop.hive.ql.io.orc.OrcInputFormat
OUTPUTFORMAT:org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat
當我們顯示的指定STORED AS INPUTFORMAT/OUTPUTFORMAT:

STORED AS INPUTFORMAT
‘org.apache.hadoop.hive.ql.io.orc.OrcInputFormat’
OUTPUTFORMAT
‘org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat’
此時SERDE並沒有指定,會使用默認的serde,在hive cli中可以通過下面cmd查看:

set hive.default.serde;
hive.default.serde=org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
當然了,如果hive-site.xml中已經配置了hive.default.fileformat,那么不知道stored as的情況下,會使用hive.default.fileformat指定的文件格式。

hive.default.fileformat ORC 參考 Hive Developer Guide has explanation on how SerDe and Storage work Hive source code- 2.3.3 8人點贊 BigData

作者:topgunviper
鏈接:https://www.jianshu.com/p/4f56cb1286a2
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM