目錄
- 概述
- SQL
- DataFrames
- Datasets
- Getting Started
- Starting Point:SQLContext
- DataFrame
- 創建 DataFrames
- DataFrame操作
- 執行SQL查詢
- Dataset
- 創建Datasets
- 與RDDs交互操作
- 使用Reflection推斷Schema
- 程序自動指定Schema
概述
Spark SQL是一個用作結構數據處理的一個模塊。不像Spark RDD中的API,Spark SQL提供給Spark更多關於數據和計算的信息。從內部來說,Spark SQL提取信息的接口經過額外的優化。有很多方法使用Spark SQL,包括SQL, DataFrames的API和Datasets的API。Spark SQL的計算引擎與語言或者API是獨立開的。這種統一意味着開發人員可以很容易在不同的APIs之間來回切換,這就提供了最自然的方式來表達一個給定的轉換。
SQL
Spark SQL可以使用基礎的SQL或者HiveQL執行SQL查詢。Spark SQL也可以被用來從已存在的Hive數據庫中讀取數據。讀取的數據庫被返回爲DataFrame。
DataFrames
如果用過R或者python的pandas庫的話,對DataFrames就特別熟悉了。直觀的角度,數據是存在類似excel表中。不理解的話可以百度一下R的DataFrame結構。
Datasets
Dataset是Spark 1,。6中新的一種接口,目前還在試驗階段,Dataset嘗試提供類似於RDDS優點的數據存取,同時又兼顧SQL的引擎優化。一個Dataset可以從JVM對象中被構造,使用transformations對數據進行操作。
Getting Started
Starting Point:SQLContext
(下面的代碼我全部使用python代碼,首先我對python比較熟悉,再者python簡潔好理解,可能工程上使用java的居多,但是目前階段需要快速,優質的掌握SparkSQL的相關概念和理論。)
Spark中SparkSQL的入口點就是SQL
Context類,或者他的派生。當然在穿件一個基礎的SQLContext之前,我們需要創建一個SparkContext。
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)
#這裏的sc是創建的SparkContext
除了使用SQLContext,我們也可以使用HiveContext,HiveContext比基礎的SQLContext提供更多的功能。這些功能暴多:使用HiveQL解析器查詢,使用Hive UDFs和從Hive tables中讀取數據的能力。比較麻煩的是HiveContext是獨立的包,有很多麻煩的依賴,如果能夠搞定這個的話,哪使用HiveContext就不成問題了。
DataFrame
創建 DataFrames
使用SQLContext,應用可以從已存的RDD中,Hive table中或者其他的數據源中創建DataFrames。
下面的例子是基於JSON文件創建一個數據框圖。
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)
df = sqlContext.read.json("examples/src/main/resources/people.json")
# Displays the content of the DataFrame to stdout
df.show()
'''這張表中的數據
{"name":"Michael"}
{"name":"Andy", "age":30}
{"name":"Justin", "age":19}
'''
DataFrame操作
DataFrame提供了一系列的方法對結構化數據進行操作。下面列出使用DataFrames進行結構化數據操作的例子。
在python中,可以使用屬性df.age和索引進行訪問。雖然前者很好用,但是極度推薦使用接口的形式。java、Scala也是使用接口來進行訪問。
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)
# 創建一個DataFrame
df = sqlContext.read.json("examples/src/main/resources/people.json")
# 顯示
df.show()
## age name
## null Michael
## 30 Andy
## 19 Justin
# 以樹結構打印數據
df.printSchema()
## root
## |-- age: long (nullable = true)
## |-- name: string (nullable = true)
# 只選擇“name”這一列
df.select("name").show()
## name
## Michael
## Andy
## Justin
# 選擇每一個人,但是年齡加一顯示出來
df.select(df['name'], df['age'] + 1).show()
## name (age + 1)
## Michael null
## Andy 31
## Justin 20
# 選擇年齡操作21歲的人
df.filter(df['age'] > 21).show()
## age name
## 30 Andy
# 按年齡計數,這個就類似SQL中的select count(*) groupby age
df.groupBy("age").count().show()
## age count
## null 1
## 19 1
## 30 1
更多的操作請參見API Documentation
執行SQL查詢
這個Ssql功能能夠確保這個程序自動運行SQL查詢,以DataFrame結構返回查詢結果。
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)
df = sqlContext.sql("SELECT * FROM table")
Dataset
創建Datasets
Datasets與RDDs類似,但是不適用Java序列和Kryo,他們使用一種特殊的編碼手段進行處理或者在網絡中進行傳輸。雖然編碼器和標準序列化都是講對象轉化爲字節,編碼器代碼動態生成和進行很多的操作比如:過濾、排序和hash沒有反序列化的字節回一個對象。
與RDDs交互操作
Spark SQL提供兩種不同的方法將已經存在的RDDs轉化成DataFrames。
* 第一種方法使用反射來推斷一個RDD包含對象的具體類型的圖式。這種reflection是當編寫Spark應用程序的時候就已經知道這些圖式,爲了讓代碼更簡潔和有效時採用的方法。
* 第二種方法是通過一種程序化的結構創建一個DataFrames,允許創建一個圖式,並讀取一個已存的RDD。這個方法更加的冗長,允許我們知道運行時才創建一個DataFrames。
使用Reflection推斷Schema
Spark SQ可以轉換行對象的RDD爲一個DataFrame,推斷數據類型。通過對鍵/值列表作爲關鍵字參數傳入Row類中的。這一列的關鍵字定義了這個表的列名,隨後通過掃描第一行推斷數據類型。因爲我們只看第一行,所以一定要確保RDD中第一行沒有缺損數據。在未來的版本中這一點會改變。
#sc是一件存在的SparkContext
from pyspark.sql import SQLContext, Row
sqlContext = SQLContext(sc)
# 讀取text文件,將每一行轉換爲一個Row
lines = sc.textFile("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])))
# 推測schema,並註冊DataFrame爲一個table
schemaPeople = sqlContext.createDataFrame(people)
schemaPeople.registerTempTable("people")
# SQL 可以在一件註冊爲table的DataFrames中執行
teenagers = sqlContext.sql("SELECT name FROM people WHERE age >= 13 AND age <= 19")
# SQL查詢的結果是RDD,並支持左右正常的RDD操作
teenNames = teenagers.map(lambda p: "Name: " + p.name)
for teenName in teenNames.collect():
print(teenName)
程序自動指定Schema
當關鍵字參數字典不能提前被定義(例如,記錄的結構是一個字符串或者文本數據集會被解析,不同用戶會有不同的項目),一個DataFrame可以通過以下三步創建:
* 從原始的RDD中創建一個set或者是lists(在java中是raw)
* 通過使用StructType匹配創建schema
* 通過SQLContext類中創建DataFrame方法將schema轉換爲RDD
比如:
# Import SQLContext and data types
from pyspark.sql import SQLContext
from pyspark.sql.types import *
# sc 是一個已存的SparkContext
sqlContext = SQLContext(sc)
# 讀取
lines = sc.textFile("examples/src/main/resources/people.txt")
parts = lines.map(lambda l: l.split(","))
people = parts.map(lambda p: (p[0], p[1].strip()))
# The schema is encoded in a string.
schemaString = "name age"
fields = [StructField(field_name, StringType(), True) for field_name in schemaString.split()]
schema = StructType(fields)
# Apply the schema to the RDD.
schemaPeople = sqlContext.createDataFrame(people, schema)
# Register the DataFrame as a table.
schemaPeople.registerTempTable("people")
# SQL can be run over DataFrames that have been registered as a table.
results = sqlContext.sql("SELECT name FROM people")
# The results of SQL queries are RDDs and support all the normal RDD operations.
names = results.map(lambda p: "Name: " + p.name)
for name in names.collect():
print(name)
基本的概念和內容就這麼多了,官方網站上還有Data Sources、性能優化、分佈式SQL引擎等等。這些方面的內容用的時候在看官方文檔