上一篇博客已經爲大家介紹完了SparkSQL的基本概念以及其提供的兩個編程抽象:DataFrame和DataSet,本篇博客,博主要爲大家介紹的是關於SparkSQL編程的內容。考慮到內容比較繁瑣,故分成了一個系列博客。本篇作爲該系列的第一篇博客,爲大家介紹的是SparkSession與DataFrame。
碼字不易,先贊後看,養成習慣!
文章目錄
SparkSQL編程
1. SparkSession
在老的版本中,SparkSQL提供兩種SQL查詢起始點:一個叫SQLContext,用於Spark自己提供的SQL查詢;一個叫HiveContext,用於連接Hive的查詢。
SparkSession是Spark最新的SQL查詢起始點,實質上是SQLContext和HiveContext的組合,所以在SQLContext和HiveContext上可用的API在SparkSession上同樣是可以使用的。SparkSession內部封裝了sparkContext,所以計算實際上是由sparkContext完成的。
2. DataFrame
2.1 創建
在Spark SQL中SparkSession是創建DataFrame和執行SQL的入口,創建DataFrame有三種方式:通過Spark的數據源進行創建;從一個存在的RDD進行轉換;還可以從Hive Table進行查詢返回。
在正式開始之前,我們需要準備數據源。
vim /opt/data/people.json
{"name":"Michael"}
{"name":"Andy", "age":30}
{"name":"Justin", "age":19}
將其上傳到集羣上。
hadoop fs -put /opt/data/people.json /input
ok~
1) 從Spark數據源進行創建
(1) 查看Spark數據源進行創建的文件格式,
spark.read.
按tab鍵表示顯示:
scala> spark.read.
csv format jdbc json load option options orc parquet schema table text textFile
(2)讀取json文件創建DataFrame
注意:spark.read.load
默認獲取parquet
格式文件
scala> val df = spark.read.json("/input/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
(3)展示結果
scala> df.show
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
2)從RDD中轉換
參照第2.5節的內容:DateFrame 轉換爲RDD
3) 從Hive Table進行查詢返回
這個將在後面的博文中涉及到,這裏暫且不談。
2.2 SQL風格語法 (主要)
1)創建一個DataFrame
scala> val df = spark.read.json("/input/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
2)對DataFrame創建一個臨時表
scala> df.createOrReplaceTempView("people")
3)通過SQL語句實現查詢全表
scala> val sqlDF = spark.sql("SELECT * FROM people")
sqlDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
4)結果展示
scala> sqlDF.show
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
注意:臨時表是Session範圍的,Session退出後,表就失效了。如果想應用範圍內仍有效,可以使用全局表。注意使用全局表時需要全路徑訪問,如:global_temp:people。
全局的臨時視圖存在於系統數據庫 global_temp中,我們必須加上庫名去引用它
5)對於DataFrame創建一個全局表
scala> df.createGlobalTempView("people")
6)通過SQL語句實現查詢全表
scala> spark.sql("select * from global_temp.people").show()
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
3. DSL 風格語法 (次要)
1)創建一個DataFrame
scala> val df = spark.read.json("/input/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
2)查看DataFrame的Schema信息
scala> df.printSchema
root
|-- age: long (nullable = true)
|-- name: string (nullable = true)
3)只查看"name"列數據
scala> df.select("name").show()
+-------+
| name|
+-------+
|Michael|
| Andy|
| Justin|
+-------+
4)查看"name"列數據以及"age+1"數據
scala> df.select($"name", $"age" + 1).show()
+-------+---------+
| name|(age + 1)|
+-------+---------+
|Michael| null|
| Andy| 31|
| Justin| 20|
+-------+---------+
5)查看"age"大於"21"的數據
scala> df.filter($"age" > 21).show()
+---+----+
|age|name|
+---+----+
| 30|Andy|
+---+----+
6)按照"age"分組,查看數據條數
scala> df.groupBy("age").count().show()
+----+-----+
| age|count|
+----+-----+
| 19| 1|
|null| 1|
| 30| 1|
+----+-----+
2.4 RDD轉換爲DateFrame
注意:如果需要RDD與DF或者DS之間操作,那麼都需要引入 import spark.implicits._
【spark不是包名,而是sparkSession對象的名稱】
準備工作:
數據文件people.txt
vim /opt/data/people.txt
zhangsan,17
lisi,20,
wangwu,19上傳至hdfs集羣
hdfs dfs -put /opt/data/people.txt /input
前置條件: 導入隱式轉換並創建一個RDD
scala> import spark.implicits._
import spark.implicits._
scala> val peopleRDD = sc.textFile("/input/people.txt")
peopleRDD: org.apache.spark.rdd.RDD[String] = examples/src/main/resources/people.txt MapPartitionsRDD[3] at textFile at <console>:27
1)通過手動確定轉換
scala> peopleRDD.map{x=>val para = x.split(",");(para(0),para(1).trim.toInt)}.toDF("name","age")
res1: org.apache.spark.sql.DataFrame = [name: string, age: int]
2)通過反射確定(需要用到樣例類)
<1>創建一個樣例類
scala> case class People(name:String, age:Int)
<2>根據樣例類將RDD轉換爲DataFrame
scala> peopleRDD.map{ x => val para = x.split(",");People(para(0),para(1).trim.toInt)}.toDF
res2: org.apache.spark.sql.DataFrame = [name: string, age: int]
3)通過編程的方式(瞭解)
<1>導入所需的類型
scala> import org.apache.spark.sql.types._
import org.apache.spark.sql.types._
<2>創建Schema
scala> val structType: StructType = StructType(StructField("name", StringType) :: StructField("age", IntegerType) :: Nil)
structType: org.apache.spark.sql.types.StructType = StructType(StructField(name,StringType,true), StructField(age,IntegerType,true))
<3>導入所需的類型
scala> import org.apache.spark.sql.Row
import org.apache.spark.sql.Row
<4>根據給定的類型創建二元組RDD
scala> val data = peopleRDD.map{ x => val para = x.split(",");Row(para(0),para(1).trim.toInt)}
data: org.apache.spark.rdd.RDD[org.apache.spark.sql.Row] = MapPartitionsRDD[6] at map at <console>:33
<5>根據數據及給定的schema創建DataFrame
scala> val dataFrame = spark.createDataFrame(data, structType)
dataFrame: org.apache.spark.sql.DataFrame = [name: string, age: int]
2.5 DateFrame 轉換爲RDD
直接調用rdd即可。
1) 創建一個DataFrame
scala> val df = spark.read.json("/input/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
2)將DataFrame轉換爲RDD
scala> val dfToRDD = df.rdd
dfToRDD: org.apache.spark.rdd.RDD[org.apache.spark.sql.Row] = MapPartitionsRDD[19] at rdd at <console>:29
3)打印RDD
scala> dfToRDD.collect
res13: Array[org.apache.spark.sql.Row] = Array([Michael, 29], [Andy, 30], [Justin, 19])
好了,本次的分享就到這裏。下一篇博客將爲大家帶來DataSet
的內容,敬請期待!!!