一、創建DataFrame/DataSet
Spark會根據文件信息嘗試着去推斷DataFrame/DataSet的Schema,當然我們也可以手動指定,手動指定的方式有以下幾種:
第1種:指定列名添加Schema
第2種:通過StructType指定Schema
第3種:編寫樣例類,利用反射機制推斷Schema
1、指定列名添加Schema
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.types._
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
object CreateDFDS2 {
def main(args: Array[String]): Unit = {
//1.創建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL").getOrCreate()
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")
//2.讀取文件
val fileRDD: RDD[String] = sc.textFile("D:\\data\\person.txt")
val linesRDD: RDD[Array[String]] = fileRDD.map(_.split(" "))
val rowRDD: RDD[Row] = linesRDD.map(line =>Row(line(0).toInt,line(1),line(2).toInt))
//3.將RDD轉成DF
//注意:RDD中原本沒有toDF方法,新版本中要給它增加一個方法,可以使用隱式轉換
//import spark.implicits._
val schema: StructType = StructType(Seq(
StructField("id", IntegerType, true),//允許爲空
StructField("name", StringType, true),
StructField("age", IntegerType, true))
)
val personDF: DataFrame = spark.createDataFrame(rowRDD,schema)
personDF.show(10)
personDF.printSchema()
sc.stop()
spark.stop()
}
}
2、StructType指定Schema
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.types._
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
object CreateDFDS2 {
def main(args: Array[String]): Unit = {
//1.創建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL").getOrCreate()
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")
//2.讀取文件
val fileRDD: RDD[String] = sc.textFile("D:\\data\\person.txt")
val linesRDD: RDD[Array[String]] = fileRDD.map(_.split(" "))
val rowRDD: RDD[Row] = linesRDD.map(line =>Row(line(0).toInt,line(1),line(2).toInt))
//3.將RDD轉成DF
//注意:RDD中原本沒有toDF方法,新版本中要給它增加一個方法,可以使用隱式轉換
//import spark.implicits._
val schema: StructType = StructType(Seq(
StructField("id", IntegerType, true),//允許爲空
StructField("name", StringType, true),
StructField("age", IntegerType, true))
)
val personDF: DataFrame = spark.createDataFrame(rowRDD,schema)
personDF.show(10)
personDF.printSchema()
sc.stop()
spark.stop()
}
}
3、反射推斷Schema--掌握
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SparkSession}
object CreateDFDS3 {
case class Person(id:Int,name:String,age:Int)
def main(args: Array[String]): Unit = {
//1.創建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL")
.getOrCreate()
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")
//2.讀取文件
val fileRDD: RDD[String] = sc.textFile("D:\\data\\person.txt")
val linesRDD: RDD[Array[String]] = fileRDD.map(_.split(" "))
val rowRDD: RDD[Person] = linesRDD.map(line =>Person(line(0).toInt,line(1),line(2).toInt))
//3.將RDD轉成DF
//注意:RDD中原本沒有toDF方法,新版本中要給它增加一個方法,可以使用隱式轉換
import spark.implicits._
//注意:上面的rowRDD的泛型是Person,裏面包含了Schema信息
//所以SparkSQL可以通過反射自動獲取到並添加給DF
val personDF: DataFrame = rowRDD.toDF
personDF.show(10)
personDF.printSchema()
sc.stop()
spark.stop()
}
}
二、花式查詢
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SparkSession}
object QueryDemo {
case class Person(id:Int,name:String,age:Int)
def main(args: Array[String]): Unit = {
//1.創建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL")
.getOrCreate()
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")
//2.讀取文件
val fileRDD: RDD[String] = sc.textFile("D:\\data\\person.txt")
val linesRDD: RDD[Array[String]] = fileRDD.map(_.split(" "))
val rowRDD: RDD[Person] = linesRDD.map(line =>Person(line(0).toInt,line(1),line(2).toInt))
//3.將RDD轉成DF
//注意:RDD中原本沒有toDF方法,新版本中要給它增加一個方法,可以使用隱式轉換
import spark.implicits._
//注意:上面的rowRDD的泛型是Person,裏面包含了Schema信息
//所以SparkSQL可以通過反射自動獲取到並添加給DF
val personDF: DataFrame = rowRDD.toDF
personDF.show(10)
personDF.printSchema()
//=======================SQL方式查詢=======================
//0.註冊表
personDF.createOrReplaceTempView("t_person")
//1.查詢所有數據
spark.sql("select * from t_person").show()
//2.查詢age+1
spark.sql("select age,age+1 from t_person").show()
//3.查詢age最大的兩人
spark.sql("select name,age from t_person order by age desc limit 2").show()
//4.查詢各個年齡的人數
spark.sql("select age,count(*) from t_person group by age").show()
//5.查詢年齡大於30的
spark.sql("select * from t_person where age > 30").show()
//=======================DSL方式查詢=======================
//1.查詢所有數據
personDF.select("name","age")
//2.查詢age+1
personDF.select($"name",$"age" + 1)
//3.查詢age最大的兩人
personDF.sort($"age".desc).show(2)
//4.查詢各個年齡的人數
personDF.groupBy("age").count().show()
//5.查詢年齡大於30的
personDF.filter($"age" > 30).show()
sc.stop()
spark.stop()
}
}
三、相互轉化
RDD、DF、DS之間的相互轉換有很多(6種),但是我們實際操作就只有2類:
1)使用RDD算子操作
2)使用DSL/SQL對錶操作
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}
object TransformDemo {
case class Person(id:Int,name:String,age:Int)
def main(args: Array[String]): Unit = {
//1.創建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL").getOrCreate()
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")
//2.讀取文件
val fileRDD: RDD[String] = sc.textFile("D:\\data\\person.txt")
val linesRDD: RDD[Array[String]] = fileRDD.map(_.split(" "))
val personRDD: RDD[Person] = linesRDD.map(line =>Person(line(0).toInt,line(1),line(2).toInt))
//3.將RDD轉成DF
//注意:RDD中原本沒有toDF方法,新版本中要給它增加一個方法,可以使用隱式轉換
import spark.implicits._
//注意:上面的rowRDD的泛型是Person,裏面包含了Schema信息
//所以SparkSQL可以通過反射自動獲取到並添加給DF
//=========================相互轉換======================
//1.RDD-->DF
val personDF: DataFrame = personRDD.toDF
//2.DF-->RDD
val rdd: RDD[Row] = personDF.rdd
//3.RDD-->DS
val DS: Dataset[Person] = personRDD.toDS()
//4.DS-->RDD
val rdd2: RDD[Person] = DS.rdd
//5.DF-->DS
val DS2: Dataset[Person] = personDF.as[Person]
//6.DS-->DF
val DF: DataFrame = DS2.toDF()
sc.stop()
spark.stop()
}
}
四、Spark SQL完成WordCount
1、SQL風格
import org.apache.spark.SparkContext
import org.apache.spark.sql.{DataFrame, Dataset, SparkSession}
object WordCount {
def main(args: Array[String]): Unit = {
//1.創建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL").getOrCreate()
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")
//2.讀取文件
val fileDF: DataFrame = spark.read.text("D:\\data\\words.txt")
val fileDS: Dataset[String] = spark.read.textFile("D:\\data\\words.txt")
//fileDF.show()
//fileDS.show()
//3.對每一行按照空格進行切分並壓平
//fileDF.flatMap(_.split(" ")) //注意:錯誤,因爲DF沒有泛型,不知道_是String
import spark.implicits._
val wordDS: Dataset[String] = fileDS.flatMap(_.split(" "))//注意:正確,因爲DS有泛型,知道_是String
//wordDS.show()
/*
+-----+
|value|
+-----+
|hello|
| me|
|hello|
| you|
...
*/
//4.對上面的數據進行WordCount
wordDS.createOrReplaceTempView("t_word")
val sql =
"""
|select value ,count(value) as count
|from t_word
|group by value
|order by count desc
""".stripMargin
spark.sql(sql).show()
sc.stop()
spark.stop()
}
}
2、DSL風格
import org.apache.spark.SparkContext
import org.apache.spark.sql.{DataFrame, Dataset, SparkSession}
object WordCount2 {
def main(args: Array[String]): Unit = {
//1.創建SparkSession
val spark: SparkSession = SparkSession.builder().master("local[*]").appName("SparkSQL").getOrCreate()
val sc: SparkContext = spark.sparkContext
sc.setLogLevel("WARN")
//2.讀取文件
val fileDF: DataFrame = spark.read.text("D:\\data\\words.txt")
val fileDS: Dataset[String] = spark.read.textFile("D:\\data\\words.txt")
//fileDF.show()
//fileDS.show()
//3.對每一行按照空格進行切分並壓平
//fileDF.flatMap(_.split(" ")) //注意:錯誤,因爲DF沒有泛型,不知道_是String
import spark.implicits._
val wordDS: Dataset[String] = fileDS.flatMap(_.split(" "))//注意:正確,因爲DS有泛型,知道_是String
//wordDS.show()
/*
+-----+
|value|
+-----+
|hello|
| me|
|hello|
| you|
...
*/
//4.對上面的數據進行WordCount
wordDS.groupBy("value").count().orderBy($"count".desc).show()
sc.stop()
spark.stop()
}
}