Spark SQL結構化數據處理

Spark SQL是Spark框架的重要組成部分, 主要用於結構化數據處理和對Spark數據執行類SQL的查詢。

DataFrame是一個分佈式的,按照命名列的形式組織的數據集合。 一張SQL數據表可以映射爲一個DataFrame對象,DataFrame是Spark SQL中的主要數據結構。

SqlContext實例是DataFrame和Spark SQL的操作入口, pyspark交互環境中已初始化了一個sqlContext實例, 在提交任務腳本時需要使用一個SparkContext來初始化:

from pyspark.sql import SQLContext
sqlContext = SqlContext(sparkContext)

本文測試環境爲Spark 2.1.0, Python API.

創建DataFrame

SqlContext.createDataFrame方法可以從python的list中創建DataFrame:

>>> data = [('a', 1, 18), ('b', 2, 22), ('c', 3, 20)]
>>> df = sqlContext.createDataFrame(data)
>>> df.collect()
[Row(_1=u'a', _2=1, _3=18), 
Row(_1=u'b', _2=2, _3=22),
Row(_1=u'c', _2=3, _3=20)]

list中的每一項成爲DataFrame中的一行, 每一列的名字默認爲_1_2_3.

同樣可以使用RDD來創建:

>>> data = [('a', 1, 18), ('b', 2, 22), ('c', 3, 20)]
>>> rdd = sc.parallelize(data)
>>> df = sqlContext.createDataFrame(rdd)
>>> df.collect()
[Row(_1=u'a', _2=1, _3=18), 
Row(_1=u'b', _2=2, _3=22),
Row(_1=u'c', _2=3, _3=20)]

或者採用更簡單的方法:

>>> df = rdd.toDF()
>>> >>> df.collect()
[Row(_1=u'a', _2=1, _3=18), 
Row(_1=u'b', _2=2, _3=22),
Row(_1=u'c', _2=3, _3=20)]

createFrame的第二個參數爲可選參數schema用於定義每一列的名稱和類型:

>>> data = [('a', 1, 18), ('b', 2, 22), ('c', 3, 20)]
>>> df = sqlContext.createDataFrame(data, ['name', 'id', 'age'])
>>> df.collect()
[Row(name=u'a', id=1, age=18), 
Row(name=u'b', id=2, age=22),
Row(name=u'c', id=3, age=20)]

同樣可以使用元素爲dict的列表創建DataFrame實例:

>>> data = [
... {'name':'a', 'id':1, 'age': 18}, 
... {'name':'b', 'id':2, 'age': 22},
... {'name':'c', 'id':3, 'age': 20}]
>>> df = sqlContext.createDataFrame(data)
>>> df.collect()
[Row(name=u'a', id=1, age=18), 
Row(name=u'b', id=2, age=22),
Row(name=u'c', id=3, age=20)]

不過Spark官方推薦使用Row對象來代替dict:

>>> from pyspark.sql import Row
>>> User = Row('name', 'id', 'age')
>>> row1 = User('a', 1, 18)
>>> row2 = User('b', 2, 22)
>>> row3 = User('b', 3, 20)
>>> data = [row1, row2, row3]
>>> df = sqlContext.createDataFrame(data)
>>> df.collect()
[Row(name=u'a', id=1, age=18), 
Row(name=u'b', id=2, age=22),
Row(name=u'c', id=3, age=20)]

schema參數也可以使用pyspark中定義的字段類型:

>>> from pyspark.sql.types import StructType, StructField
>>> from pyspark.sql.types import StringType, IntegerType
>>> schema = StructType([
... StructField("name", StringType(), True),  # name, type, nullable
... StructField("id", IntegerType(), True),
... StructField("age", IntegerType(), True)])
>>> data = [('a', 1, 18), ('b', 2, 22), ('c', 3, 20)]
>>> df = sqlContext.createDataFrame(data, schema)
>>> df.collect()
[Row(name=u'a', id=1, age=18), 
Row(name=u'b', id=2, age=22), 
Row(name=u'c', id=3, age=20)]

更多關於createDataFrame方法的信息可以參考官方文檔

SqlContext.read是一個pyspark.sql.DataFrameReader對象, 它可以用於根據外部數據源創建DataFrame, 包括讀取文件和使用jdbc讀取數據庫。

詳情可以參考官方文檔

DataFrame操作

DataFrame提供了一些常用操作的實現, 可以使用這些接口查看或修改DataFrame:

  • df.collect(): 以Row列表的方式顯示df中的所有數據
  • df.show(): 以可視化表格的方式打印df中的所有數據
  • df.count(): 顯示df中數據的行數
  • df.describe() 返回一個新的DataFrame對象包含對df中數值列的統計數據
  • df.cache(): 以MEMORY_ONLY_SER方式進行持久化
  • df.persist(level): 以指定的方式進行持久化
  • df.unpersist(): 刪除緩存

DataFrame的一些屬性可以用於查看它的結構信息:

  • df.columns: 返回各列名稱的列表

  • df.schema: 以StructType對象的形式返回df的表結構

  • df.dtypes: 以列表的形式返回每列的名稱和類型。
    [('name', 'string'), ('id', 'int')]

  • df.rdd 將DataFrame對象轉換爲rdd

DataFrame支持使用Map和Reduce操作:

  • df.map(func): 等同於df.rdd.map(func)

  • df.reduce(func): 等同於 df.rdd.reduce(func)

DataFrame的結構可以進行一些修改:

  • df.drop(col): 返回一個刪除指定列後的DataFrame對象:
>>> df.drop('age')
DataFrame[age:int, id: int]
>>>df.drop(df.name)
DataFrame[age:int, id: int]

同樣可以查詢DataFrame中特定的記錄:

  • df.take(index): 以列表的形式返回df的前n條記錄, 下標從1開始

  • df.first(): 返回df中的第一個Row對象

  • df.filter(cond): 返回只包含滿足條件記錄的新DataFrame對象

>>> df.filter(df.age>=20).collect()
[Row(name=u'b', id=2, age=22), Row(name=u'c', id=3, age=20)]
  • df.select(col): 返回只包含指定列的新DataFrame對象:
>>> df.select('*').collect()
[Row(name=u'a', id=1, age=18), Row(name=u'b', id=2, age=22), Row(name=u'c', id=3, age=20)]

>>> df.select(df.id, df.age-1).collect()
[Row(id=1, (age - 1)=17), Row(id=2, (age - 1)=21), Row(id=3, (age - 1)=19)]
  • df.join(other, on=None, how=None)將df和other兩個DataFrame對象連接爲一個DataFrame對象.
  • on: 指定連接的列
  • how: 指定連接方式:'inner''outer''left_outer''right_outer''leftsemi', 默認爲'inner'
>>> df.collect()
[Row(name=u'a', id=1, age=18), Row(name=u'b', id=2, age=22), Row(name=u'c', id=3, age=20)]
>>> df2.collect()
[Row(id=1, nation=u'cn'), Row(id=2, nation=u'us'), Row(id=4, nation=u'uk')]

>>> df.join(df2, 'id').collect()
[Row(id=1, name=u'a', age=18, nation=u'cn'), Row(id=2, name=u'b', age=22, nation=u'us')]
  • df.limit(num): 返回一個新的DataFrame對象, 其記錄數不超過num, 多餘的記錄將被刪除.

  • df.distinct() : 返回一個新的去除重複行後的DataFrame對象

更多信息可以參考官方文檔

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