本文主要介紹RDD、DataFrame和DataSet這三者到底有什麼差別,主要介紹以下幾個方面:
- 分别出現在spark的哪些版本?
- 各自的優缺點是什麼?
- 應該如何選擇使用哪個類别?
分别出現在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特性:
- 非強類型(untyped),DataSet[Row]是泛型對象的集合,它的别名是DataFrame;
- 強類型(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]
上述代碼,經曆了三段過程:
- Spark讀取了JSON檔案,并根據定義的結構,建立了一個DataFrame的資料集
- 在這個DataFrame的資料集,即Dataset[Row]中,實際是一個個的行對象,因為它并不知道各自的類型
- 最後,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呢?
- 如果你想要豐富的語義、高層次的抽象,和特定情景的API,使用DataFrame或DataSet。
- 如果你的處理要求涉及到filters, maps, aggregation, averages, sum, SQL queries, columnar access或其他lambda匿名函數,使用DataFrame或DataSet。
- 如果希望在編譯時獲得更高的類型安全性,需要類型化的JVM對象,利用Tungsten編碼進行高效的序列化、反序列化,使用DataSet。
- 如果你想統一和簡化spark的API,使用DataFrame或DataSet。
- 如果你是一個R使用者,使用DataFrame。
- 如果你是一個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