Spark SQL, DataFrames and Datasets Guide

目錄

  • 概述 
    • 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引擎等等。這些方面的內容用的時候在看官方文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章