Spark處理Json格式數據(Python)


前言
 
Spark能夠自動推斷出Json數據集的“數據模式”(Schema),並將它加載為一個SchemaRDD實例。這種“自動”的行為是通過下述兩種方法實現的:
 
jsonFile:從一個文件目錄中加載數據,這個目錄中的文件的每一行均為一個JSON字符串(如果JSON字符串“跨行”,則可能導致解析錯誤);
 
jsonRDD:從一個已經存在的RDD中加載數據,這個RDD中的每一個元素均為一個JSON字符串;
 
這里我們僅討論jsonFile的場景,jsonRDD處理方法類似。
 
典型示例
 
JSON的數據模式是非常靈活的,我們例舉常見的幾種可能性進行討論。
 
(1)JSON文件中的數據模式一致,每一行的數據均為JSON字符串(非JSON數組)
 
假設數據模式包含三個屬性:id、name、birthdate,測試數據如下所示:
 
 
Python測試代碼如下:
 
 
在終端上執行可以看到有兩部分輸出:
 
 
 
可以看到數據模式一致的情況下,數據模式被正確推斷,數據被正確解析。
 
(2)JSON文件中的數據模式一致,每一行的數據均為JSON數組字符串
 
假設數據模式包含三個屬性:id、name、birthdate,測試數據如下所示:
 
 
Python測試代碼同上,在終端上執行可以看到有兩部分輸出:
 
 
 
可以看到數據數據模式被正確推斷,JSON數組中的“多個”對象數據被正確解析,解析結果共有三行。
 
(3)JSON文件中的數據模式一致,但每一行數據以兩種形式出現:JSON字符串(非數組)、JSON數組字符串
 
假設數據模式包含三個屬性:id、name、birthdate,測試數據如下所示:
 
 
其中第一行為JSON數組字符串,包含有兩個JSON對象;第二行為JSON字符串,表示一個JSON對象。
 
Python測試代碼同上,在終端上執行可以看到有兩部分輸出:
 
 
 
可以看到數據行混搭的情況下(同時包含JSON字符串(非數組)和JSON數組字符串),數據數據模式被正確推斷,數據被正確解析。
 
(4)JSON文件中的數據模式不一致
 
假設數據模式有以下兩種情況:
 
模式一:id、name、birthdate
模式二:id、name、birthdate、weight
 
測試數據如下所示:
 
 
其中第一行數據為JSON數組字符串,數據模式為模式一;第二行數據為JSON字符串(非數組),數據模式為模式二。
 
Python測試代碼同上,在終端上執行可以看到有兩部分輸出:
 
 
 
可以看到數據模式被推斷為模式二,數據也是按照模式二被解析;模式二相對於模式一多出一個屬性“weight”,如果數據匹配模式一,則屬性“weigth”的值以“None”的形式出現。
 
數據模式不一致還有一種比較復雜的情況:模式交錯,如下:
 
模式一:id、name、birthdate、height
模式二:id、name、birthdate、weight
 
測試數據如下所示:
 
 
Python測試代碼同上,在終端上執行可以看到有兩部分輸出:
 
 
 
可以看出數據模式被推斷為模式一與模式二的並集,缺失的屬性以“None”的形式出現。
 
結論:數據模式不一致時,推斷模式為多個數據模式的並集。
 
(5)JSON文件中的數據模式不一致,且數據模式存在類型多樣以及嵌套的情況;
 
模式一:id、name、birthdate、msg、extras
模式二:id、name、birthdate、weight
 
測試數據如下所示:
 
 
第一行是一個JSON數組字符串,包含兩個JSON字符串,每個JSON字符串的屬性msg是一個JSON字符串,屬性extras是一個JSON數組字符串。
 
Python測試代碼同上,在終端上執行可以看到有兩部分輸出:
 
 
 
可以看出數據模式被推斷為模式一與模式二的並集,其中msg被解析為struct類型,extras被解析為array類型(元素類型為struct),缺失的屬性以“None”的形式出現。
 
如果我們需要處理的JSON數據的模式是不一致的(對象屬性不一致),我們在代碼邏輯中如何進行判斷呢?以(5)中的測試數據為例,屬性weight並不是出現在所有數據行中,為了避免運行時拋出異常,需要根據是否包含屬性weight作出不同的處理,這時就需要用到Python內建函數hasattr,如下:
 
 
代碼中函數handle的作用:如果對象row含有屬性weight,則返回對應的屬性值;否則返回“no value”。而判斷row是否含有屬性“weight”是使用函數hasattr實現的。
 
通過上述的幾個示例我們可以發現Spark可以正確應對常見的JSON日志格式,但我們在充分利用JSON特性的同時(日志屬性靈活擴展、JSON處理方式統一),也應該考慮合理設計JSON日志數據模式,避免數據模式不一致或數據模式復雜給數據分析帶來的不便。
 
jsonFile相當於是Spark提供給我們的便利工具,省去了我們自己解析JSON數據的麻煩,但也可能會出現工具失效的情況,大部分原因來自於數據格式不統一或不規范,此時我們就得自己解析JSON數據。
 
Python自帶了一個操作JSON數據的庫“json”,我們會經常使用到兩個方法:
 
dumps:用於JSON對象序列化,即JSON對象 —> JSON字符串
 
loads:用於JSON字符串反序列化,即JSON字符串 —> JSON對象
 
方法使用示例如下所示:
 
 
解決了JSON數據的序列化與反序列化的問題后,還需要考慮一個情況:
 
數據分析時多數需要處理的都是文本數據,我們將一行文本(字符串)反序列化為一個JSON對象后,我們如何判斷這個對象是一個普通JSON對象,還是一個JSON數組?特別是我們需要根據不同的數據類型進行不同的處理時,這種數據類型的判斷就不可避免。
 
此時我們就需要用到Python的內建函數:isinstance,如下所示:
 
 
在終端執行上述代碼,可得結果:
 
 
可以看出JSON數組對象的類型為“list”,而普通JSON對象的類型為“dict”。
 
總結
 
Spark在處理JSON數據時通常可以直接使用jsonFile,如果數據格式不統一、不規范或者我們需要更為靈活的數據處理方式時,則可以將文本數據以字符串的形式按行讀入,然后使用Python JSON相關庫、內建函數自行解析JSON數據。
 
 
 
 
 


免責聲明!

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



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