2021-05-12 14:32:11
Spark 處理中文亂碼問題(UTF-8編碼)
問題場景
要用spark處理一大堆微信紀錄檔資料,紀錄檔存放在HDFS上,是xml格式,裡面有大量的中文。用scala + java實現了xml的處理邏輯,其中有一步是要獲取xml中的一個title欄位,中文。不管怎麼抓取,最終得到的中文都會變成一堆“?????”,亂碼了。從xml中獲取非中文欄位,沒有任何問題。也就是說,程式碼的邏輯是沒什麼問題的。
問題解析
直接用Hadoop fs -text或者hadoop fs -cat檢視HDFS上的檔案,是可以正常顯示的,也就是說HDFS上存放的原資料是好的。那麼就肯定是讀取資料或者處理資料的過程中出了問題。spark on yarn的資料處理,同時涉及了HDFS,App driver, App excutor之間的互動,所以還真沒法一下就判斷出是哪一步傳輸中出了問題。抽絲剝繭,先梳理一遍spark的處理邏輯:
(1) 從HDFS把xml讀取到每個NM上的executor中(spark on yarn環境)
(2) 在executor中對xml進行處理,獲取中文欄位。這裡我實現了一個java方法,呼叫dom來解析xml。
(3) 把解析後的欄位collect到driver中,做儲存或者輸出列印等。
(4) 或者把解析後的欄位重新存入HDFS
進入Spark-shell,依次驗證這幾個步驟。讀入HDFS上的xml檔案,然後直接寫入HDFS,檢查發現字元顯示正常,排除步驟(1)(4)。讀入HDFS上的xml檔案,collect到driver中,然後println,字元顯示正常,排除步驟(3)。說明問題出在executor對欄位的解析處理過程中。
無論漢字還是英文字元,本質上還是一組位元組流,所以出現亂碼,只能是編碼解析出了問題。檢視發現,程式碼中只有一個地方對xml檔案中的字元做了解析,就是這裡:
DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder(); InputStream strm = new ByteArrayInputStream(xmlStream.getBytes()); Document doc = dbBuilder.parse(strm);
把string轉為inputStream的過程。 找到了出問題的位置,下一步就是檢測。
登入到executor所在的hadoop節點,進入spark-shell, 輸入System.getProperty("file.encoding"),返回”ISO-8859-1“,說明它的預設編碼方式是ISO-8859-1。另一種檢測方法,是定義一個String變數等於一個漢字,然後a.getBytes().length。檢查它的位元組數,並推斷對應的字元編碼。UTF8漢字占3個位元組,GBK漢字占2個位元組。
ISO-8895-1占1位元組,用ISO-8895-1的方式把漢字轉成位元組流,然後轉回的過程中,肯定會損失一部分資料,所以會亂碼。
問題定位到後,解決就很簡單了。 在所有涉及到位元組轉換時,一定要指定編碼方式。類似這樣:
String -> Byte:
string.getBytes("UTF-8")
Byte -> String:
new String(bytes, "UTF-8")
更多Spark相關教學見以下內容:
CentOS 7.0下安裝並設定Spark http://www.linuxidc.com/Linux/2015-08/122284.htm
Spark1.0.0部署指南 http://www.linuxidc.com/Linux/2014-07/104304.htm
Spark官方文件 - 中文翻譯 http://www.linuxidc.com/Linux/2016-04/130621.htm
CentOS 6.2(64位元)下安裝Spark0.8.0詳細記錄 http://www.linuxidc.com/Linux/2014-06/102583.htm
Spark簡介及其在Ubuntu下的安裝使用 http://www.linuxidc.com/Linux/2013-08/88606.htm
安裝Spark叢集(在CentOS上) http://www.linuxidc.com/Linux/2013-08/88599.htm
Hadoop vs Spark效能對比 http://www.linuxidc.com/Linux/2013-08/88597.htm
Spark安裝與學習 http://www.linuxidc.com/Linux/2013-08/88596.htm
Spark 平行計算模型 http://www.linuxidc.com/Linux/2012-12/76490.htm
Ubuntu 14.04 LTS 安裝 Spark 1.6.0 (偽分散式) http://www.linuxidc.com/Linux/2016-03/129068.htm
相關文章