【Spark SQL】6、常用API的學習

所有功能的入口點都是SparkSession類。要創建基本的SparkSession,只需使用SparkSession.builder()

import org.apache.spark.sql.SparkSession

val spark = SparkSession
  .builder()
  .appName("Spark SQL basic example")
  .config("spark.some.config.option", "some-value")
  .getOrCreate()

在Spark 2.0中,DataFrame只是Scala和Java API中的行數據集。與強類型的Scala / Java數據集附帶的“類型轉換”相反,這些操作也稱爲“非類型轉換”。

// This import is needed to use the $-notation
import spark.implicits._
// Print the schema in a tree format
df.printSchema()
// root
// |-- age: long (nullable = true)
// |-- name: string (nullable = true)

// Select only the "name" column
df.select("name").show()
// +-------+
// |   name|
// +-------+
// |Michael|
// |   Andy|
// | Justin|
// +-------+

// Select everybody, but increment the age by 1
df.select($"name", $"age" + 1).show()
// +-------+---------+
// |   name|(age + 1)|
// +-------+---------+
// |Michael|     null|
// |   Andy|       31|
// | Justin|       20|
// +-------+---------+

// Select people older than 21
df.filter($"age" > 21).show()
// +---+----+
// |age|name|
// +---+----+
// | 30|Andy|
// +---+----+

// Count people by age
df.groupBy("age").count().show()
// +----+-----+
// | age|count|
// +----+-----+
// |  19|    1|
// |null|    1|
// |  30|    1|
// +----+-----+

除了簡單的列引用和表達式外,數據集還具有豐富的函數庫,包括字符串處理,日期算術,通用數學運算等。

SparkSession上的sql函數使應用程序能夠以編程方式運行SQL查詢,並將結果作爲DataFrame返回。

import org.apache.spark.sql.SparkSession

val spark = SparkSession
  .builder()
  .appName("Spark SQL basic example")
  .config("spark.some.config.option", "some-value")
  .getOrCreate()
val df=spark.read.json("/Users/wojiushiwo/json/people.json")
// Register the DataFrame as a SQL temporary view
df.createOrReplaceTempView("people")

val sqlDF = spark.sql("SELECT * FROM people")
sqlDF.show()

全局臨時view

Spark SQL中的臨時視圖是會話範圍的,如果創建它的會話終止,它將消失.如果要在所有會話之間共享一個臨時視圖並保持活動狀態,直到Spark應用程序終止,則可以創建全局臨時視圖。全局臨時視圖與系統保留的數據庫global_temp相關聯,我們必須使用限定名稱來引用它,如select * from global_temp.view1

// Register the DataFrame as a global temporary view
df.createGlobalTempView("people")

// Global temporary view is tied to a system preserved database `global_temp`
spark.sql("SELECT * FROM global_temp.people").show()
// +----+-------+
// | age|   name|
// +----+-------+
// |null|Michael|
// |  30|   Andy|
// |  19| Justin|
// +----+-------+

// Global temporary view is cross-session
spark.newSession().sql("SELECT * FROM global_temp.people").show()
// +----+-------+
// | age|   name|
// +----+-------+
// |null|Michael|
// |  30|   Andy|
// |  19| Justin|
// +----+-------+

創建數據集

數據集與RDD相似,但是它們不是使用Java序列化或Kryo,而是使用專用的Encoder對對象進行序列化以進行網絡處理或傳輸。編碼器和標準序列化都負責將對象轉換爲字節,編碼器是動態生成的代碼,並使用允許Spark執行許多操作(例如過濾,排序和散列,而無需將字節反序列化爲對象)。

// Note: Case classes in Scala 2.10 can support only up to 22 fields. To work around this limit,
// you can use custom classes that implement the Product interface
case class Person(name: String, age: Long)

// Encoders are created for case classes
val caseClassDS = Seq(Person("Andy", 32)).toDS()
caseClassDS.show()
// +----+---+
// |name|age|
// +----+---+
// |Andy| 32|
// +----+---+

// Encoders for most common types are automatically provided by importing spark.implicits._
val primitiveDS = Seq(1, 2, 3).toDS()
primitiveDS.map(_ + 1).collect() // Returns: Array(2, 3, 4)

// DataFrames can be converted to a Dataset by providing a class. Mapping will be done by name
val path = "examples/src/main/resources/people.json"
val peopleDS = spark.read.json(path).as[Person]
peopleDS.show()
// +----+-------+
// | age|   name|
// +----+-------+
// |null|Michael|
// |  30|   Andy|
// |  19| Justin|
// +----+-------+

與RDD互操作

Spark SQL支持兩種將現有RDD轉換爲數據集的方法。第一種方法使用反射來推斷包含特定類型對象的RDD的架構。這種基於反射的方法可以使代碼更簡潔,當您在編寫Spark應用程序時已經瞭解架構時,可以很好地工作。

創建數據集的第二種方法是通過編程界面,該界面允許您構造模式,然後將其應用於現有的RDD。儘管此方法較爲冗長,但可以在運行時才知道列及其類型的情況下構造數據集。

使用反射推斷架構

Spark SQL的Scala接口支持自動將包含case class的RDD轉換爲DataFrame。case class定義表的架構。case class的參數名稱使用反射讀取,併成爲列的名稱。 Case類也可以嵌套或包含複雜類型,例如Seqs或Arrays。可以將該RDD隱式轉換爲DataFrame,然後將其註冊爲表。可以在後續的SQL語句中使用表。

object App {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession
      .builder()
      .master("local[2]")
      .appName("Spark SQL basic example")
      .config("spark.some.config.option", "some-value")
      .getOrCreate()

    import spark.implicits._
    
    case class Person(name:String,age:Long)
    val dataFrame = spark.sparkContext.textFile("/Users/wojiushiwo/json/people.text")
      .map(_.split(","))
      .map(s => Person(s(0), s(1).trim().toInt))
      .toDF()
    dataFrame.show()

    spark.stop()
  }

}

報錯信息:value toDF is not a member of org.apache.spark.rdd.RDD[Person]

解決方案:將case class放到main函數外

object App {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession
      .builder()
      .master("local[2]")
      .appName("Spark SQL basic example")
      .config("spark.some.config.option", "some-value")
      .getOrCreate()

    import spark.implicits._
    
    val dataFrame = spark.sparkContext.textFile("/Users/wojiushiwo/json/people.text")
      .map(_.split(","))
      .map(s => Person(s(0), s(1).trim().toInt))
      .toDF()
    dataFrame.show()

    spark.stop()
  }
    case class Person(name:String,age:Long)

}

數據源

Spark SQL支持通過DataFrame接口對各種數據源進行操作。 DataFrame可以使用關係轉換進行操作,也可以用於創建臨時視圖。將DataFrame註冊爲臨時視圖使您可以對其數據運行SQL查詢。

發佈了101 篇原創文章 · 獲贊 22 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章