什麼是Spark SQL
Spark SQL是Apache Spark用於處理結構化數據的模塊。Spark SQL允許使用SQL或熟悉的DataFrame API查詢Spark程序內的結構化數據。Spark SQL支持多語言編程包括Java、Scala、Python和R,可以根據自身喜好進行選擇。本文中所涉及的Spark SQL代碼示例均使用python語言。
Spark SQL的核心-DataFrame
DataFrame是一個以命名列(類似於關係表中的字段)組織的分佈式數據集。可以把它看成關係數據庫中的一張表或R/python中的DataFrame數據結構(在spark 1.3以前,稱爲schema-RDD,後改爲DataFrame)。
DataFrame可以通過多種來源創建:結構化數據文件,hive的表,外部數據庫或者RDDs
Spark SQL的使用
Spark SQL所有的功能入口都是SQLContext 類,及其子類。不過要創建一個SQLContext對象,首先需要有一個SparkContext對象,然後再創建SQLContext
from pyspark import SparkContext
from pyspark import SQLContext
sc = SparkContext("local","my_pyspark")
spark = SQLContext(sc)
除了SQLContext之外,你也可以創建HiveContext,HiveContext是SQLContext 的超集。
創建DataFrame
數據來源可以是已有的RDD、或Hive表、或其他數據源
以下是一個從JSON文件創建DataFrame的小例子:
df = spark.read.json("/usr/local/spark/examples/src/main/resources/people.json") #自帶的示例文件,可在安裝路徑下查找
df.show() #展示DataFrame的內容
以下是一個從RDD創建DataFrame的小例子:
from pyspark import Row
rdd = sc.parallelize([
Row(name='Michael',age=29),
Row(name='Andy', age=30),
Row(name='Justin', age=19)
])
df1 = spark.createDataFrame(rdd)
df1.show()
從文本文件創建DataFrame的小例子:
rdd2 = sc.textFile("/usr/local/spark/examples/src/main/resources/people.txt")
df2 = spark.createDataFrame(rdd)
df2.show()
DataFrame操作
df.printSchema() #打印數據的樹形結構
df.select("name").show()#查詢name字段
df.select(df['name'], df['age'] + 1).show()#查詢每個人的name和age字段,但age加1
df.filter(df['age'] > 21).show()#篩選年齡大於21的
df.groupBy("age").count().show()#按年齡統計人數
運行SQL查詢
SQLContext.sql可以執行SQL查詢,並返回DataFrame結果。
df.createOrReplaceTempView("people")#將DataFrame註冊爲SQL臨時視圖
sqlDF = spark.sql("SELECT * FROM people")
sqlDF.show()
全局臨時視圖
Spark SQL中的臨時視圖是會話範圍的,如果創建它的會話終止,將會消失。 如果您希望在所有會話之間共享一個臨時視圖並保持活動狀態,直到Spark應用程序終止,則可以創建一個全局臨時視圖。 全局臨時視圖與系統保存的數據庫global_temp綁定,我們必須使用限定名稱來引用它,例如, SELECT * FROM global_temp.view1。
df.createGlobalTempView("people1")
spark.sql("SELECT * FROM global_temp.people1").show()
spark.newSession().sql("SELECT * FROM global_temp.people1").show()
DataFrame與RDD的互相轉換
Spark SQL將現有RDD轉換爲Datasets的方法有兩種。
1. 使用反射機制,推導包含指定類型對象RDD的schema。這種基於反射機制的方法使代碼更簡潔,而且如果你事先知道數據schema,推薦使用這種方式;
2. 編程方式構建一個schema,然後應用到指定RDD上。這種方式更囉嗦,但如果你事先不知道數據有哪些字段,或者數據schema是運行時讀取進來的,那麼你很可能需要用這種方式。
第一種方法使用反射來推斷包含特定類型對象的RDD的模式。這種基於反射的方法導致更簡潔的代碼,並且在編寫Spark應用程序時已經知道模式的情況下運行良好。
創建數據集的第二種方法是通過編程接口,允許您構建模式,然後將其應用於現有的RDD。雖然這個方法比較冗長,但是它允許你在構造數據集的時候直到運行時才知道列和它們的類型
利用反射推導schema
Spark SQL可以將Row對象的RDD轉換爲DataFrame,從而推斷出數據類型。 行是通過將一個鍵/值對列表作爲kwargs傳遞給Row類來構造的。 此列表的鍵定義了表的列名,類型是通過對整個數據集進行採樣來推斷的,類似於在JSON文件上執行的推斷。
from pyspark import SparkContext
from pyspark.sql import Row
from pyspark import SQLContext
sc = SparkContext()
spark = SQLContext(sc)
#加載一個文本文件,並將每行轉換爲一個Row對象。
lines = sc.textFile("/usr/local/spark/examples/src/main/resources/people.txt")#換成自己的地址
parts = lines.map(lambda l: l.split(","))
people = parts.map(lambda p: Row(name=p[0], age=int(p[1])))
#
schemaPeople = spark.createDataFrame(people)
schemaPeople.createOrReplaceTempView("people")
teenagers = spark.sql("SELECT name FROM people WHERE age >= 13 AND age <= 19")
teenNames = teenagers.rdd.map(lambda p: "Name: " + p.name).collect()
for name in teenNames:
print(name)
結果:
編程方式定義schema
from pyspark import SparkContext
from pyspark.sql.types import *
from pyspark import SQLContext
sc = SparkContext()
spark = SQLContext(sc)
# 加載文本文件
lines = sc.textFile("/usr/local/spark/examples/src/main/resources/people.txt")
#分割每一行
parts = lines.map(lambda l: l.split(","))
# 將每一行都轉換爲一個元組
people = parts.map(lambda p: (p[0], p[1].strip()))
# 可以理解爲定義列表佔位符
# schemaString = "name age"
fields = [StructField(field_name, StringType(), True) for field_name in schemaString.split()]
schema = StructType(fields)
# 將schema應用到指定RDD上
schemaPeople = spark.createDataFrame(people, schema)
# 使用DataFrame創建一個臨時視圖
schemaPeople.createOrReplaceTempView("people")
# SQL可以通過已註冊爲表的DataFrame運行。
results = spark.sql("SELECT name FROM people")
results.show()
結果:
參考文檔:http://spark.apache.org/docs/2.2.1/sql-programming-guide.html