天天看點

RDD、DataFrame和DataSet的差別是什麼

rdd、dataframe和dataset是容易産生混淆的概念,必須對其互相之間對比,才可以知道其中異同。

rdd和dataframe

RDD、DataFrame和DataSet的差別是什麼

rdd-dataframe

上圖直覺地展現了dataframe和rdd的差別。左側的rdd[person]雖然以person為類型參數,但spark架構本身不了解 person類的内部結構。而右側的dataframe卻提供了詳細的結構資訊,使得spark sql可以清楚地知道該資料集中包含哪些列,每列的名稱和類型各是什麼。dataframe多了資料的結構資訊,即schema。rdd是分布式的 java對象的集合。dataframe是分布式的row對象的集合。dataframe除了提供了比rdd更豐富的算子以外,更重要的特點是提升執行效率、減少資料讀取以及執行計劃的優化,比如filter下推、裁剪等。

提升執行效率

rdd api是函數式的,強調不變性,在大部分場景下傾向于建立新對象而不是修改老對象。這一特點雖然帶來了幹淨整潔的api,卻也使得spark應用程式在運作期傾向于建立大量臨時對象,對gc造成壓力。在現有rdd api的基礎之上,我們固然可以利用mappartitions方法來重載rdd單個分片内的資料建立方式,用複用可變對象的方式來減小對象配置設定和gc的開銷,但這犧牲了代碼的可讀性,而且要求開發者對spark運作時機制有一定的了解,門檻較高。另一方面,spark sql在架構内部已經在各種可能的情況下盡量重用對象,這樣做雖然在内部會打破了不變性,但在将資料傳回給使用者時,還會重新轉為不可變資料。利用 dataframe api進行開發,可以免費地享受到這些優化效果。

減少資料讀取

分析大資料,最快的方法就是 ——忽略它。這裡的“忽略”并不是熟視無睹,而是根據查詢條件進行恰當的剪枝。

上文讨論分區表時提到的分區剪 枝便是其中一種——當查詢的過濾條件中涉及到分區列時,我們可以根據查詢條件剪掉肯定不包含目标資料的分區目錄,進而減少io。

對于一些“智能”資料格 式,spark sql還可以根據資料檔案中附帶的統計資訊來進行剪枝。簡單來說,在這類資料格式中,資料是分段儲存的,每段資料都帶有最大值、最小值、null值數量等 一些基本的統計資訊。當統計資訊表名某一資料段肯定不包括符合查詢條件的目标資料時,該資料段就可以直接跳過(例如某整數列a某段的最大值為100,而查詢條件要求a > 200)。

此外,spark sql也可以充分利用rcfile、orc、parquet等列式存儲格式的優勢,僅掃描查詢真正涉及的列,忽略其餘列的資料。

執行優化

RDD、DataFrame和DataSet的差別是什麼

人口資料分析示例

為了說明查詢優化,我們來看上圖展示的人口資料分析的示例。圖中構造了兩個dataframe,将它們join之後又做了一次filter操作。如果原封不動地執行這個執行計劃,最終的執行效率是不高的。因為join是一個代價較大的操作,也可能會産生一個較大的資料集。如果我們能将filter 下推到 join下方,先對dataframe進行過濾,再join過濾後的較小的結果集,便可以有效縮短執行時間。而spark sql的查詢優化器正是這樣做的。簡而言之,邏輯查詢計劃優化就是一個利用基于關系代數的等價變換,将高成本的操作替換為低成本操作的過程。

得到的優化執行計劃在轉換成物 理執行計劃的過程中,還可以根據具體的資料源的特性将過濾條件下推至資料源内。最右側的實體執行計劃中filter之是以消失不見,就是因為溶入了用于執行最終的讀取操作的表掃描節點内。

對于普通開發者而言,查詢優化 器的意義在于,即便是經驗并不豐富的程式員寫出的次優的查詢,也可以被盡量轉換為高效的形式予以執行。

rdd和dataset

dataset以catalyst邏輯執行計劃表示,并且資料以編碼的二進制形式被存儲,不需要反序列化就可以執行sorting、shuffle等操作。

dataset創立需要一個顯式的encoder,把對象序列化為二進制,可以把對象的scheme映射為sparksql類型,然而rdd依賴于運作時反射機制。

通過上面兩點,dataset的性能比rdd的要好很多。

dataframe和dataset

dataset可以認為是dataframe的一個特例,主要差別是dataset每一個record存儲的是一個強類型值而不是一個row。是以具有如下三個特點:

dataset可以在編譯時檢查類型

并且是面向對象的程式設計接口。用wordcount舉例:

後面版本dataframe會繼承dataset,dataframe是面向spark sql的接口。

dataframe和dataset可以互相轉化, df.as[elementtype] 這樣可以把dataframe轉化為dataset, ds.todf() 這樣可以把dataset轉化為dataframe。

本文作者:jacksu

來源:51cto