天天看點

基于spark的Scala程式設計—RDD、DataFrame和DataSet的差別

本文主要介紹RDD、DataFrame和DataSet這三者到底有什麼差別,主要介紹以下幾個方面:

  1. 分别出現在spark的哪些版本?
  2. 各自的優缺點是什麼?
  3. 應該如何選擇使用哪個類别?

分别出現在spark的哪些版本?

RDD是spark一開始就提出的概念,DataFrame是spark1.3.0版本提出來的,spark1.6.0版本又引入了DateSet的,但是在spark2.0版本中,DataFrame和DataSet合并為DataSet。

各自的優缺點是什麼?

資料結構 優點 缺點
RDD

1.相比于傳統的MapReduce架構,Spark在RDD中内置很多函數操作,group,map,filter等,友善處理結構化或非結構化資料。

2.面向對象程式設計,直接存儲的java對象,類型轉化也安全

1.由于它基本和hadoop一樣萬能的,是以沒有針對特殊場景的優化,比如對于結構化資料處理相對于sql來比非常麻煩

2.預設采用的是java序列号方式,序列化結果比較大,而且資料存儲在java堆記憶體中,導緻gc比較頻繁

DataFrame

1.結構化資料處理非常友善,支援Avro, CSV, elastic search, and Cassandra等kv資料,也支援HIVE tables, MySQL等傳統資料表

2.有針對性的優化,如采用Kryo序列化,由于資料結構元資訊spark已經儲存,序列化時不需要帶上元資訊,大大的減少了序列化大小,而且資料儲存在堆外記憶體中,減少了gc次數,是以運作更快。

3.hive相容,支援hql、udf等

1.編譯時不能類型轉化安全檢查,運作時才能确定是否有問題

2.對于對象支援不友好,rdd内部資料直接以java對象存儲,dataframe記憶體存儲的是row對象而不能是自定義對象

Dataset

1.DateSet整合了RDD和DataFrame的優點,支援結構化和非結構化資料

2.和RDD一樣,支援自定義對象存儲

3.和DataFrame一樣,支援結構化資料的sql查詢

4.采用堆外記憶體存儲,gc友好

5.類型轉化安全,代碼友好

自Spark2.0之後,DataFrame和DataSet合并為更進階的DataSet,新的DataSet具有兩個不同的API特性:

  1. 非強類型(untyped),DataSet[Row]是泛型對象的集合,它的别名是DataFrame;
  2. 強類型(strongly-typed),DataSet[T]是具體對象的集合,如scala和java中定義的類;

注: 因為Python和R沒有編譯階段,是以隻有無類型的API,即DataFrame。

靜态類型和運作時類型安全

例如,在用Spark SQL進行查詢時,直到運作時才會發現(syntax error)文法錯誤(這樣成本太高),而采用DataFrame和DataSet時,可以在編譯時就可以發現錯誤(進而節省開發時間和成本)。換句話說,如果你在DataFrame中調用的一個函數不是API的一部分,編譯器會捕獲這個錯誤。但是,對于一個不存在的列名,在編譯期是檢測不出來的。

由于DataSet都表示為lambda匿名函數和JVM類型對象,是以編譯時會檢測到類型參數的任何不比對。另外,在使用DataSet時,也可以在編譯時檢測到分析錯誤,進而節省開發人員的時間和成本。

結構化和半結構化資料的進階抽象和自定義視圖

DataFrames作為一個行式資料集的集合,可以将半結構化的資料以結構化的視圖呈現出來。例如,您有一個海量的物聯網裝置資料集,以JSON表示。由于JSON是一種半結構化的格式,可以通過DataSet[DeviceIoTData]将強類型資料表達出來。

可以通過Scala定義一個類DeviceIoTData:

這樣,我們就可以從JSON檔案中讀取資料了:

// read the json file and create the dataset from the case class DeviceIoTData
// ds is now a collection of JVM Scala objects DeviceIoTData
val ds = spark.read.json(“/databricks-public-datasets/data/iot/iot_devices.json”).as[DeviceIoTData]
           

上述代碼,經曆了三段過程:

  1. Spark讀取了JSON檔案,并根據定義的結構,建立了一個DataFrame的資料集
  2. 在這個DataFrame的資料集,即Dataset[Row]中,實際是一個個的行對象,因為它并不知道各自的類型
  3. 最後,spark将Dataset[Row]轉換為Dataset[DeviceIoTData],每一行資料被轉化為了一個個的執行個體對象

API結構的易用性

雖然結構化會限制Spark對資料的操作,但是DataSet引入了豐富的API來對高結構化的資料進行控制,例如,在進行agg, select, sum, avg, map, filter, 或者groupBy操作時,DataSet比RDD更簡單。

性能和優化

因為DataFrame和DataSet的API是建立在Spark SQL引擎之上的,無論是java、scala還是python,所有涉及到關系型查詢的語句,都會經曆相同的邏輯優化和執行計劃。不同的是, Dataset[T]類的API更适合資料工程任務,Dataset[Row](即DataFrame)類的API則更适合互動式分析。而且,spark作為一種編譯器可以了解DataSet中的JVM對象,可以通過Tungsten編碼,将這些對象進行快速的序列化和反序列化。

我們應該什麼時候使用DataFrame或DataSet呢?

  1. 如果你想要豐富的語義、高層次的抽象,和特定情景的API,使用DataFrame或DataSet。
  2. 如果你的處理要求涉及到filters, maps, aggregation, averages, sum, SQL queries, columnar access或其他lambda匿名函數,使用DataFrame或DataSet。
  3. 如果希望在編譯時獲得更高的類型安全性,需要類型化的JVM對象,利用Tungsten編碼進行高效的序列化、反序列化,使用DataSet。
  4. 如果你想統一和簡化spark的API,使用DataFrame或DataSet。
  5. 如果你是一個R使用者,使用DataFrame。
  6. 如果你是一個Python使用者,使用DataFrame,如果你需要更多的控制功能,盡量回到RDD。

如何選擇RDD還是DataFrame/DataSet?

前者提供低級别的功能和更多的控制,後者允許自定義視圖和結構,提供進階和特定領域的操作,節省空間,并能夠以極高的速度執行。

本文的很多内容參考:

1.https://www.zhihu.com/question/48684460

2.https://databricks.com/blog/2016/07/14/a-tale-of-three-apache-spark-apis-rdds-dataframes-and-datasets.html

繼續閱讀