Spark RDD、DataFrame和DataSet的區別


 

目錄(?)[+]

 

轉載請標明出處:小帆的帆的專欄

RDD

優點:

  1. 編譯時類型安全 
    編譯時就能檢查出類型錯誤
  2. 面向對象的編程風格 
    直接通過類名點的方式來操作數據

缺點:

  1. 序列化和反序列化的性能開銷 
    無論是集群間的通信, 還是IO操作都需要對對象的結構和數據進行序列化和反序列化.
  2. GC的性能開銷 
    頻繁的創建和銷毀對象, 勢必會增加GC
 
import org.apache.spark.sql.SQLContext import org.apache.spark.{SparkConf, SparkContext} object Run { def main(args: Array[String]) { val conf = new SparkConf().setAppName("test").setMaster("local") val sc = new SparkContext(conf) sc.setLogLevel("WARN") val sqlContext = new SQLContext(sc) /** * id age * 1 30 * 2 29 * 3 21 */ case class Person(id: Int, age: Int) val idAgeRDDPerson = sc.parallelize(Array(Person(1, 30), Person(2, 29), Person(3, 21))) // 優點1 // idAge.filter(_.age > "") // 編譯時報錯, int不能跟String比 // 優點2 idAgeRDDPerson.filter(_.age > 25) // 直接操作一個個的person對象 } }

 

DataFrame

DataFrame引入了schema和off-heap

  • schema : RDD每一行的數據, 結構都是一樣的. 這個結構就存儲在schema中. Spark通過schame就能夠讀懂數據, 因此在通信和IO時就只需要序列化和反序列化數據, 而結構的部分就可以省略了.

  • off-heap : 意味着JVM堆以外的內存, 這些內存直接受操作系統管理(而不是JVM)。Spark能夠以二進制的形式序列化數據(不包括結構)到off-heap中, 當要操作數據時, 就直接操作off-heap內存. 由於Spark理解schema, 所以知道該如何操作.

off-heap就像地盤, schema就像地圖, Spark有地圖又有自己地盤了, 就可以自己說了算了, 不再受JVM的限制, 也就不再收GC的困擾了.

通過schema和off-heap, DataFrame解決了RDD的缺點, 但是卻丟了RDD的優點. DataFrame不是類型安全的, API也不是面向對象風格的.

 
import org.apache.spark.sql.types.{DataTypes, StructField, StructType} import org.apache.spark.sql.{Row, SQLContext} import org.apache.spark.{SparkConf, SparkContext} object Run { def main(args: Array[String]) { val conf = new SparkConf().setAppName("test").setMaster("local") val sc = new SparkContext(conf) sc.setLogLevel("WARN") val sqlContext = new SQLContext(sc) /** * id age * 1 30 * 2 29 * 3 21 */ val idAgeRDDRow = sc.parallelize(Array(Row(1, 30), Row(2, 29), Row(4, 21))) val schema = StructType(Array(StructField("id", DataTypes.IntegerType), StructField("age", DataTypes.IntegerType))) val idAgeDF = sqlContext.createDataFrame(idAgeRDDRow, schema) // API不是面向對象的 idAgeDF.filter(idAgeDF.col("age") > 25) // 不會報錯, DataFrame不是編譯時類型安全的 idAgeDF.filter(idAgeDF.col("age") > "") } }

 

DataSet

DataSet結合了RDD和DataFrame的優點, 並帶來的一個新的概念Encoder

當序列化數據時, Encoder產生字節碼與off-heap進行交互, 能夠達到按需訪問數據的效果, 而不用反序列化整個對象. Spark還沒有提供自定義Encoder的API, 但是未來會加入.

下面看DataFrame和DataSet在2.0.0-preview中的實現

下面這段代碼, 在1.6.x中創建的是DataFrame

 
// 上文DataFrame示例中提取出來的
val idAgeRDDRow = sc.parallelize(Array(Row(1, 30), Row(2, 29), Row(4, 21))) val schema = StructType(Array(StructField("id", DataTypes.IntegerType), StructField("age", DataTypes.IntegerType))) val idAgeDF = sqlContext.createDataFrame(idAgeRDDRow, schema)

 

但是同樣的代碼在2.0.0-preview中, 創建的雖然還叫DataFrame

 
// sqlContext.createDataFrame(idAgeRDDRow, schema) 方法的實現, 返回值依然是DataFrame
def createDataFrame(rowRDD: RDD[Row], schema: StructType): DataFrame = { sparkSession.createDataFrame(rowRDD, schema) }

 

但是其實卻是DataSet, 因為DataFrame被聲明為Dataset[Row]

 
package object sql {
  // ...省略了不相關的代碼 type DataFrame = Dataset[Row] }

 

因此當我們從1.6.x遷移到2.0.0的時候, 無需任何修改就直接用上了DataSet.

下面是一段DataSet的示例代碼

 
import org.apache.spark.sql.types.{DataTypes, StructField, StructType} import org.apache.spark.sql.{Row, SQLContext} import org.apache.spark.{SparkConf, SparkContext} object Test { def main(args: Array[String]) { val conf = new SparkConf().setAppName("test").setMaster("local") // 調試的時候一定不要用local[*] val sc = new SparkContext(conf) val sqlContext = new SQLContext(sc) import sqlContext.implicits._ val idAgeRDDRow = sc.parallelize(Array(Row(1, 30), Row(2, 29), Row(4, 21))) val schema = StructType(Array(StructField("id", DataTypes.IntegerType), StructField("age", DataTypes.IntegerType))) // 在2.0.0-preview中這行代碼創建出的DataFrame, 其實是DataSet[Row] val idAgeDS = sqlContext.createDataFrame(idAgeRDDRow, schema) // 在2.0.0-preview中, 還不支持自定的Encoder, Row類型不行, 自定義的bean也不行 // 官方文檔也有寫通過bean創建Dataset的例子,但是我運行時並不能成功 // 所以目前需要用創建DataFrame的方法, 來創建DataSet[Row] // sqlContext.createDataset(idAgeRDDRow) // 目前支持String, Integer, Long等類型直接創建Dataset Seq(1, 2, 3).toDS().show() sqlContext.createDataset(sc.parallelize(Array(1, 2, 3))).show() } }

 

 

參考

Introducing Apache Spark Datasets 
APACHE SPARK: RDD, DATAFRAME OR DATASET? 
RDD、DataFrame和DataSet的區別 
Spark 2.0.0-preview 官方文檔


免責聲明!

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



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