spark 三種建立 資料集的方法,及測試(Scala程式碼)

強子no2發表於2018-06-14

1 通過建立RDD執行查詢

/**
  *
  * 優點:
  *
  * 編譯時型別安全
  * 編譯時就能檢查出型別錯誤
  * 物件導向的程式設計風格
  * 直接通過類名點的方式來運算元據
  * 缺點:
  *
  * 序列化和反序列化的效能開銷
  * 無論是叢集間的通訊, 還是IO操作都需要對物件的結構和資料進行序列化和反序列化.
  * GC的效能開銷
  * 頻繁的建立和銷燬物件, 勢必會增加GC
  */
def rddTest(): Unit ={
  val conf = new SparkConf().setAppName("test").setMaster("local")
  val sc = new SparkContext(conf)
  sc.setLogLevel("WARN")
  val sqlContext = new SQLContext(sc)

  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).take(1000).foreach(println); // 直接操作一個個的person物件
}

2  通過  DataFrame引入了schema和off-heap

**
  *
  * 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也不是物件導向風格的.
  */
def dataFrameTest(): Unit ={

  val conf = new SparkConf().setAppName("test").setMaster("local")
  val sc = new SparkContext(conf)
  sc.setLogLevel("WARN")
  val sqlContext = new SQLContext(sc)

  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).take(1000).foreach(println);
  // 不會報錯, DataFrame不是編譯時型別安全的
  idAgeDF.filter(idAgeDF.col("age") > "").take(1000).foreach(println);
}
3 DataSet結合了RDD和DataFrame的優點, 並帶來的一個新的概念Encoder
**
  * DataSet結合了RDD和DataFrame的優點, 並帶來的一個新的概念Encoder
  *
  * 當序列化資料時, Encoder產生位元組碼與off-heap進行互動, 能夠達到按需訪問資料的效果, 而不用反序列化整個物件. Spark還沒有提供自定義Encoder的API, 但是未來會加入.
  *
  * 下面看DataFrame和DataSet在2.0.0-preview中的實現
  */
def dataSetTest(): Unit ={

  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)

  idAgeDS.registerTempTable("test")

  sqlContext.sql("SELECT * FROM test").show()

  // 在2.0.0-preview中, 還不支援自定的Encoder, Row型別不行, 自定義的bean也不行
  // 官方文件也有寫通過bean建立Dataset的例子,但是我執行時並不能成功
  // 所以目前需要用建立DataFrame的方法, 來建立DataSet[Row]
  // sqlContext.createDataset(idAgeRDDRow)

  // 目前支援String, Integer, Long等型別直接建立Dataset
  //Seq(1, 2, 3).toDS().take(1000).foreach(println);
  //sqlContext.createDataset(sc.parallelize(Array(1, 2, 3))).take(1000).foreach(println);
}

4 通過Main 方法呼叫

def main(args: Array[String]): Unit = { //建立spark的執行環境
  rddTest()
  dataFrameTest()
  dataSetTest()
}




相關文章