目录
1.DataFrame组成
DataFrame是一个二维表结构,那么表格结构就有无法绕开的三个点:
1.行
2.列
3.表结构描述
比如,在MySQL中的一张表:
1.由许多行组成
2.数据也被分成多个列
3.表也有表结构信息(列,列名,列类型,列约束等)
基于这个前提,DataFrame的组成如下:
在结构层面
1.StructType对象描述整个DataFrame的表结构
2.StructField对象描述一个列的信息
在数据层面
1.Row对象记录一行数据
2.Column对象记录一列数据并包含列的信息
2.DataFrame的代码构建
2.1基于RDD方式1
通过SparkSession对象的createDataFrame方法来将RDD转换为DataFrame。
# coding:utf8
from pyspark.sql import SparkSession
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
# 基于RDD转换成DataFrame
rdd = sc.textFile("../data/people.txt").\
map(lambda x: x.split(',')).\
map(lambda x:[x[0], int(x[1])])
# 构建DataFrame对象
# 参数1 被转换的RDD
# 参数2 指定列名,通过list的形式指定,按照顺序依次提供字符串名称即可
df = spark.createDataFrame(rdd, schema=['name', 'age'])
# 打印DataFrame的表结构
df.printSchema()
# 打印df中的数据
# 参数1 表示 展示多少条数据,默认不传是20
# 参数2 表示是否对列进行截断,如果列的数据长度超过20个字符串长度,后续内容不不显示 以....代替
# 如果给False 表示不截断全部显示,默认是True
df.show(20, False)
# 输出
root
|-- name: string (nullable = true)
|-- age: long (nullable = true)
+-----+---+
|name |age|
+-----+---+
|Bob |20 |
|Alice|29 |
|Join |33 |
+-----+---+
2.2 基于RDD方式2
通过StuctType对象来定义DataFrame的 “表结构”转换RDD
# coding:utf8
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
# 基于RDD转换成DataFrame
rdd = sc.textFile("../data/people.txt").\
map(lambda x: x.split(',')).\
map(lambda x:[x[0], int(x[1])])
# 构建表结构的描述对象:StructType对象
schema = StructType().add("name", StringType(),nullable=True).\
add("age", IntegerType(), nullable=False)
# 基于StructType对象去构建RDD到DF的转换
df = spark.createDataFrame(rdd, schema=schema)
df.printSchema()
df.show()
# 输出
root
|-- name: string (nullable = true)
|-- age: integer (nullable = false)
+-----+---+
| name|age|
+-----+---+
| Bob| 20|
|Alice| 29|
| Join| 33|
+-----+---+
2.3 基于RDD方式3
使用RDD的toDF方法转换RDD
# coding:utf8
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
# 基于RDD转换成DataFrame
rdd = sc.textFile("../data/people.txt").\
map(lambda x: x.split(',')).\
map(lambda x:[x[0], int(x[1])])
# toDF的方法构建DataFrame
df1 = rdd.toDF(["name", "age"])
df1.printSchema()
df1.show()
# toDF的方式2 通过StructType来构建
schema = StructType().add("name", StringType(), nullable=True). \
add("age", IntegerType(), nullable=False)
df2 = rdd.toDF(schema=schema)
df2.printSchema()
df2.show()
# 输出
root
|-- name: string (nullable = true)
|-- age: long (nullable = true)
+-----+---+
| name|age|
+-----+---+
| Bob| 20|
|Alice| 29|
| Join| 33|
+-----+---+
root
|-- name: string (nullable = true)
|-- age: integer (nullable = false)
+-----+---+
| name|age|
+-----+---+
| Bob| 20|
|Alice| 29|
| Join| 33|
+-----+---+
2.4 基于Pandas的DataFrame
将Pandas的DataFrame对象,转变为分布式的SparkSQL DataFrame对象
2.5 读取外部数据
通过SparkSQL的统一API进行数据读取构建DataFrame
2.5.1 读取 text文件源
# coding:utf8
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
# 构建StructType,text数据源,读取数据的特点是,将一整行值作为一个列读取,默认列名为value,类型为string
schema = StructType().add("data", StringType(), nullable=True)
df = spark.read.format("text").\
schema(schema=schema).\
load('../data/people.txt')
df.printSchema()
df.show()
# 输出
root
|-- data: string (nullable = true)
+---------+
| data|
+---------+
| Bob, 20|
|Alice, 29|
| Join, 33|
+---------+
进程已结束,退出代码0
2.5.2 读取json数据源
# coding:utf8
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
# 构建StructType,text数据源,读取数据的特点是,将一整行值作为一个列读取,默认列名为value,类型为string
# JSON类型自带Schema信息
df = spark.read.format('json').load('../data/people.json')
df.printSchema()
df.show()
#输出
root
|-- age: long (nullable = true)
|-- name: string (nullable = true)
+----+-----+
| age| name|
+----+-----+
|null| Bob|
| 22|Alice|
| 33| json|
+----+-----+
2.5.3 读取csv数据源
# coding:utf8
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
df = spark.read.format('csv').\
option("sep", ',').\
option("header", False).\
option("encoding", "utf-8").\
schema("name STRING, age INT, job STRING").\
load('../data/people.csv')
df.printSchema()
df.show()
# 输出
root
|-- name: string (nullable = true)
|-- age: integer (nullable = true)
|-- job: string (nullable = true)
+-----+---+-------+
| name|age| job|
+-----+---+-------+
| Bob| 12|Student|
|Alice| 23|Teacher|
| Jon| 14| Manger|
+-----+---+-------+
2.6 写出DataFrame数据
统一语法:
df.write.mode().format().option (K, V).save(PATH)
# mode, 传入模式字符串可选:append 追加, overwrite 覆盖, ignore 忽略, error 重复就报异常(默认)
# 注意 text 源 只支持单列 df 写出
# option 设置属性, 如: .option( "sep" , " , ")r
# save 写出的路径, 支持本地文件和HDFS
3 DataFrame的入门操作
DataFrame支持两种风格进行编程,分别是:
——DSL风格
——SQL风格
3.1 DSL语法风格
DSL称之为:领域特定语言
其实就是指DataFrame的特有API
DSL风格意思就是以调用API的方式来处理Data
例如:df.where().limit()
# coding:utf8
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
df = spark.read.format('csv'). \
option("sep", ','). \
option("header", False). \
option("encoding", "gbk"). \
schema("id INT, subject STRING, score INT"). \
load("..\data\stu_score.csv")
# Column对象的获取
id_column = df['id']
subject_column = df['subject']
# DSL语法风格
df.select(["id", "subject"]).show()
df.select("id", "subject").show()
df.select(id_column, subject_column).show()
# filter API
df.filter("score < 90").show()
df.filter(df["score"]<99).show()
# where API
df.where("score < 90").show()
df.where(df["score"] < 99).show()
# groupBy
df.groupBy("subject").count().show()
df.groupBy(df["subject"]).count().show()
3.2 SQL语法风格
SQL风格就是使用SQL语句处理DataFrame的数据
例如:spark.sql(" SELECT * FROM xx)
注册DataFrame成为表
DataFrame的一个强大之处就是我们可以将它看作是一个关系型数据表,然后可以通过程序中
使用spark.sql()来执行SQL语句查询,结果返回一个DataFrame。
如果想使用SQL风格的语法,需要将DataFrame注册成表,采用如下的方式
df.createTempView("score") # 注册一个临时视图(表)
df.createOrReplaceTempView("score") # 注册一个临时图,如果存在进行替换
df.createGlobalTempView("score") # 注册一个全局表
全局表:跨SparkSession对象使用,在一个程序内的多个SparkSession中均可调用,查询前带上前缀: global_temp.
临时表:只在当前SparkSession中可用
# coding:utf8
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StringType, IntegerType
if __name__ == '__main__':
# 构建执行环境入口对象SparkSession
spark = SparkSession.builder.appName("test").master("local[*]").getOrCreate()
sc = spark.sparkContext
df = spark.read.format('csv'). \
option("sep", ','). \
option("header", False). \
option("encoding", "gbk"). \
schema("id INT, subject STRING, score INT"). \
load("..\data\stu_score.csv")
# 注册成临时表
df.createTempView("score") # 注册一个临时视图(表)
df.createOrReplaceTempView("score_2") # 注册一个临时图,如果存在进行替换
df.createGlobalTempView("score_3") # 注册一个全局表 在使用的时候需要在前面带上 global_temp. 前缀
# 可以通过SparkSession对象的sql api 来完成sql 语句的执行
spark.sql("SELECT subject, COUNT(*) AS cnt FROM score GROUP BY subject").show()
spark.sql("SELECT subject, COUNT(*) AS cnt FROM score_2 GROUP BY subject").show()
spark.sql("SELECT subject, COUNT(*) AS cnt FROM global_temp.score_3 GROUP BY subject").show()
# 输出
+-------+---+
|subject|cnt|
+-------+---+
| 语文| 14|
| 数学| 12|
+-------+---+
+-------+---+
|subject|cnt|
+-------+---+
| 语文| 14|
| 数学| 12|
+-------+---+
+-------+---+
|subject|cnt|
+-------+---+
| 语文| 14|
| 数学| 12|
+-------+---+