【大數據學習】SparkSQL之 DataFrame與RDD的互操作

根據官網介紹:Spark SQL支持兩種不同的方法將現有的RDDs轉換爲數據集。第一種方使用反射來推斷包含特定對象類型的RDD的模式。這種基於反射的方法可以生成更簡潔的代碼,並且當您在編寫Spark應用程序時已經知道模式時,這種方法可以很好地工作。這種方式雖然簡單,但是不通用;因爲生產中的字段是非常非常多的。創建數據集的第二種方法是通過編程接口,該接口允許您構造模式,然後將其應用於現有的RDD。雖然這個方法更詳細,但它允許您在列及其類型直到運行時才知道時構造數據集。爲什麼要轉成RDD呢,因爲我們大部分的數據都在HDFS上的。

下面用例子來說明兩種用法:

object DFApp {

  def main(args: Array[String]): Unit = {

    val sparkSession= SparkSession.builder()

      .appName("DFApp")

      .master("local[2]")

      .getOrCreate()

    inferReflection(sparkSession)

    //    val lines=sc.textFile("file:///E:/data.txt")

    sparkSession.stop()

  }


  /**********************************DataFrame和RDD的互操作  反射的方式 *******************************/

  def inferReflection(sparkSession: SparkSession): Unit ={
    val info=sparkSession.sparkContext.textFile("file:///E:/data.txt")

    //****用反射的方式將RDD轉換成DataFrame需要導入隱式轉換。import 後面的名字不是固定的,而是sparksession的名字,因爲前面創建的sparksession叫做sparkSession,所以就用sparkSession.implcits._  ****//

    import sparkSession.implicits._

    val df=info.map(_.split("\t")).map(x=>Info(x(0),x(1),x(2).toLong)).toDF()

    df.show()


    //基於DataFrame的API編程
    df.groupBy("domain").sum("responseSize").show()

    //基於sql API編程,把DataFrame註冊成一張臨時表,表名info
    df.createOrReplaceTempView("info")
    sparkSession.sql("select domain,sum(responseSize) from info group by domain").show()

  }

  //注意:用反射的方式把RDD轉DataFrame需要用到case class,case class 需要建在main方法以外,否則會報錯
  case class Info(ip:String,domain:String,responseSize:Long)

}
show()的輸出結果:

 

上面的例子是用第一個方法實現的,但是不建議使用,因爲在工作當中,使用這種方式是有限制的。 對於以前的版本來說,case class最多支持22個字段如果超過了22個字段,我們就必須要自己開發一個類,實現product接口才行。因此這種方式雖然簡單,但是不通用;因爲生產中的字段是非常非常多的,是不可能只有20來個字段的。 

下面介紹第二個方法

以編程的方式指定DataFrame,這種方式用得非常多。通過編程方式指定schema ,對於第一種方式的schema其實定義在了case class裏面了。 

官網解讀:如果不能提前定義case(例如,記錄的結構編碼在字符串中,或者文本數據集將被解析,字段將針對不同的用戶以不同的方式投影),因爲在實際業務處理中,你的字段可能在變化,因此很難去提前定義,這時則可以通過三個步驟以編程方式創建數據DataFrame

  1. Create an RDD of Rows from the original RDD;

           從原始RDD創建行RDD

      2.Create the schema represented by a StructType matching the structure of Rows in the RDD created in Step 1.

          創建由StructType表示的模式,該結構類型與步驟1中創建的RDD中的行結構匹配

      3.Apply the schema to the RDD of Rows via createDataFrame method provided by SparkSession.

         通過SparkSession提供的createDataFrame方法將模式應用於行RDD

 

object DFApp {
  def main(args: Array[String]): Unit = {
    val sparkSession= SparkSession.builder()
      .appName("DFApp")
      .master("local[2]")
      .getOrCreate()

    //    val lines=sc.textFile("file:///E:/data.txt")

   programmatically(sparkSession)
   sparkSession.stop()
  }

def  programmatically(sparkSession: SparkSession): Unit ={
 
val info=sparkSession.sparkContext.textFile("file:///E:/data.txt")

 
import sparkSession.implicits._

 
//1 Create an RDD of Rows from the original RDD,即從原始的RDD創建一個Rows類型的RDD
 
val rdd=info.map(_.split("\t")).map(x=>Row(x(0),x(1),x(2).toLong)) 

  //2.定義schema,使用structType來指定
 
val struct= types.StructType(
    Array(
    StructField(
"ip", StringType, true),
    StructField(
"domain", StringType, false),
    StructField(
"responseSize", LongType, false)
    )
  )

 
// 3.把這個schema作用到RDD的Rows上。通過sparkSession.createDataFrame方法
 
val df=sparkSession.createDataFrame(rdd,struct)
  df.show()
}

運行後同樣可以得到結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章