目录
【私信发ipynb文件】
DataFrame的建立
类似传统数据库的二维表,包括自身数据和数据结构信息(Schema)
在Spark中,DataFrame支持嵌套数据类型,如array和map
DataFrame可以从多种数据来源上进行构建,如结构化数据文件、Hive中的表、外部数据库或现有RDD
import findspark
findspark.init()
from pyspark.sql import SparkSession
# 构建Spark对象
# 采用local模式,只使用一个CPU进行处理
# 使用getOrCreate()共享SparkContext。如果尚不存在,则创建SparkContext;如果已存在,则创建SparkContext的实例。
# getOrCreate使用参考链接:https://www.codenong.com/47813646/
spark = SparkSession.builder \
.master("local[1]") \
.appName("RDD Demo") \
.getOrCreate();
sc = spark.sparkContext
a = [('Jack',32), ('Smith',33)]
df = spark.createDataFrame(a)
df.collect()
df.show()
df2 = spark.createDataFrame(a, ['name', 'age'])
df2.collect()
df2.show()
使用ROW创建
rdd = sc.parallelize(a)
print(rdd.collect())
from pyspark.sql import Row
# 创建一个包含列名的Row
Person = Row('name', 'age')
# 将RDD对象进行元素映射,转换成一个Person对象,并返回一个新的RDD对象,格式为[Row(name='Jack', age=32), Row(name='Smith', age=33)]
person = rdd.map(lambda r: Person(*r))
print(person.collect())
df = spark.createDataFrame(person)
df.collect()
创建具有字段类型的
from pyspark.sql.types import *
schema = StructType([
# True代表是否可以为空
StructField('name', StringType(), True),
StructField('age', StringType(), True)
])
df = spark.createDataFrame(rdd, schema)
print(df.collect())
# print('\n')
print(df.show())
# print('\n')
# 打印df对象的Schema结构定义
print(df.printSchema())
更简单的方法
df = spark.createDataFrame(rdd, 'name:string, age:int')
df.collect()
df.printSchema()
# 提取第一个元素作为新的RDD
rdd2 = rdd.map(lambda row:row[0])
df2 = spark.createDataFrame(rdd2, 'string')
df2.collect()
df2.show()
df2.printSchema()
Spark SQL 基本用法
a = [('Jack',32), ('Smith',33), ('李四',35)]
rdd = sc.parallelize(a)
df = spark.createDataFrame(rdd, 'name:string, age:int')
df.count()
# 创建一个名为user的表,存入df的数据
df.createOrReplaceTempView('user')
df2 = spark.sql('select count(*) as counter from user')
df2.show()
自定义函数
conf = sc.getConf().get('spark.sql.shuffle.partitions')
print(conf)
# 利用该方法注册一个自定义用户函数strLen,其逻辑是返回参数的长度
strlen = spark.udf.register('strLen', lambda x:len(x))
df2 = spark.sql('select *, strLen(name) as len from user')
df2.show()
对数据的操作
df2 = df.select('name').where(strlen('name')>2)
df2.show()
# df.agg({key,value})
# key指字段
# value指执行的逻辑
df2 = df.agg({'age':'max'})
df2.show()
# 进行统计描述
df.describe(['age']).show()
写入文件 & 从文件读取
# 写入文件
df.write.parquet('myuser.parquet')
# 从文件导入
peopleDF = spark.read.parquet('myuser.parquet')
peopleDF.show()
进入jupyter目录下可以看见有一个文件夹,里面有四个文件
peopleDF.filter(peopleDF.age>32).show()
关联查询
# 创建第一个表
a = [
('01', '张三', '男', 32,5000),
('01', '李四', '男', 33,6000),
('01', '王五', '女', 38,5500),
('02', 'Jack', '男', 42,7000),
('02', 'Smith', '女', 27,6500),
('02', 'Lily', '女', 45,9500),
]
rdd = sc.parallelize(a)
peopleDf = spark.createDataFrame(rdd, 'deptId:string, name:string, gender:string, age:int, salary:int')
peopleDf.show()
# 创建第二个表
b = [
('01', '销售部'),
('02', '研发部')
]
rdd2 = sc.parallelize(b)
deptDf = spark.createDataFrame(rdd2, 'id:string, name:string')
deptDf.show()
method默认为inner,
也可选
cross, uter, full, full_outer, left, left_outer, right, right_outer, left_semi, left_anti
# 进行连接
# df1.join(df2, action, method)
# action是条件,method是连接方式
peopleDf.join(deptDf, peopleDf.deptId == deptDf.id, 'inner') \
.groupBy(deptDf.name, 'gender') \
.agg({'salary':'avg', 'age':'max'}) \
.show()
【若需要去重,只需要在show()之前调用 .distinct() 即可 】
【若要删去某一列,在show()之前调用 .drop('列名1', '列名2') 】
从行上移除数据
【从一个DataFrame中移除另一个DataFrame的数据】
df1 = spark.createDataFrame([('a',1), ('a',1), ('a',1), ('a',2), ('b',3), ('c',4)], ['c1', 'c2'])
df2 = spark.createDataFrame([('b', 3), ('a',1)], ['c1', 'c2'])
df1.exceptAll(df2).show()
# 从df1中删除df2
# 若有重复数据,只排除一个
【求交集】
print(df1.show())
print(df2.show())
df1.intersectAll(df2).sort('c1','c2').show()
【空值处理】
a = [
('01', '张三', '男', 32,5000),
('01', '李四', '男', 33,6000),
('01', '王五', '女', 38,5500),
('02', 'Jack', '男', 42,7000),
('02', 'Smith', '女', 27,6500),
('02', 'Lily', '女', 45,None),
]
rdd = sc.parallelize(a)
peopleDf = spark.createDataFrame(rdd, 'deptId:string, name:string, gender:string, age:int, salary:int')
peopleDf.show()
peopleDf.na.fill({'salary':0, 'name':'unknown'}).show()
None值显示为null,.na.fill()进行替换
【综合操作示例】
a = [
('01', '张三', '男', 32,5000),
('01', '李四', '男', 33,6000),
('01', '王五', '女', 38,5500),
('02', 'Jack', '男', 42,7000),
('02', 'Smith', '女', 27,6500),
('02', 'Lily', '女', 45,9500),
]
rdd = sc.parallelize(a)
peopleDf = spark.createDataFrame(rdd, 'deptId:string, name:string, gender:string, age:int, salary:int')
# 转成JSON格式
print(peopleDf.toJSON().collect())
# 给出对象的概览统计结果
peopleDf.summary().show()
# 添加age2列
peopleDf.withColumn('age2', peopleDf.age+1) \
.withColumnRenamed('name', '姓名') \
.show()
# 选择表达式
peopleDf.selectExpr('age+1', 'salary*1.2').show()
Spark读取JSON数据
去jupyter目录下新建 user.json文件,添加下面的内容
{"deptId":"01","name":"张三","gender":"男","age":32,"salary":5000},
{"deptId":"01","name":"李四","gender":"男","age":33,"salary":6000},
{"deptId":"01","name":"王五","gender":"女","age":38,"salary":5500},
{"deptId":"02","name":"Jack","gender":"男","age":42,"salary":7000},
{"deptId":"02","name":"Smith","gender":"女","age":27,"salary":6500},
{"deptId":"02","name":"Lily","gender":"女","age":45,"salary":9500}
# JSON数据不能有[]
# 从user.json目录下读取文件,并转换成DataFrame对象
df = spark.read.format('json').load('user.json')
df.show()
# 打印字段类型
df.dtypes
# 透视
# 按照deptId分组,将genedr字段的值转置到列,形成透视表,汇总字段为salary的和
df2 = df.groupBy('deptId').pivot('gender').sum('salary')
df2.show()
# 条件选择
# df.salary.between(6000,9500)是一个字段表达式,而不是类似where子句的过滤
df.select('name', df.salary.between(6000,9500)).show()
# 选择name和age两列,筛选条件是 df.name.like(‘Smi%’)
df.select('name', 'age').where(df.name.like('Smi%')).show()
Spark对日期数据进行处理
df = spark.createDataFrame([('2020-05-10',), ('2020-05-09',)], ['dt'])
from pyspark.sql.functions import add_months
# add_months(df.dt, 1) 对dt字段进行+1处理,计算下个月日期
# alias('next_month') 对字段进行重命名
df.select(add_months(df.dt, 1).alias('next_month')).show()
将DataFrame对象存入csv文件并读取
# 从user.json目录下读取文件,并转换成DataFrame对象
df = spark.read.format('json').load('user.json')
df.show()
# 写入csv文件(其实对应一个目录,不是传统csv文件)
# 写入模式有两种 append追加模式;overwrite覆盖模式
# 给定的是数据存储的路径,而非存储的文件名
df.write.csv('user.csv', 'append')
# 读取csv文件
spark.read.csv('user.csv').show()