SparkSQL?
SparkSQL是Spark中专门为结构化数据计算的模块,基于SparkCore之上
特点
- Integrated:集成了大多数的开发接口【Python、Scala、Java、SQL】
- Uniform Data Access:统一化的数据访问【集成了大量读写数据源接口】
- Hive Integration:Hive的集成【兼容90%以上Hive的语法:DDL、DML、DQL】
- Standard Connectivity:标准的数据连接接口【JDBC、SQL文件、Python文件】
SparkCore和SparkSQL对比
DataFrame的设计
本质
DataFrame = RDD + Schema
# Schema是元数据的抽象集合,包括表、列、数据类型、视图、存储过程等
区别
# JSON数据源文件
{"name":"Michael", "salary":3000}
{"name":"Andy", "salary":4500}
{"name":"Justin", "salary":3500}
{"name":"Berta", "salary":4000}
RDD读取
input_rdd = spark.sparkContext.textFile("../data/json")
input_rdd.foreach(lambda x: print(x))
# 会将每条数据作为一个字符串,进行输出,并不会解析数据中有列
DataFrame读取
input_df = spark.read.json("../data/json")
input_df.printSchema()
input_df.show()
从DataFrame中获取RDD和Schema
# 关系 DataFrame = RDD + Schema
# 从Df中获取RDD
input_df_rdd = input_df.rdd
input_df_rdd.foreach(lambda x: print(x))
# 从DF中获取Schema
input_df_schema = input_df.schema
print(*input_df_schema)
DataFrame的创建
# 创建DataFrame即创建SparkSession
spark = SparkSession.builder.master("local[2]").appName("SparkSession").getOrCreate()
自动推断类型转换
# 当数据源是半结构化数据或者特殊格式的数据,不能直接使用SparkSQL进行处理
# 先用SparkCore将非结构化数据进行清洗转化成结构化数据,然后使用SparkSQL进行统计分析
# 自动推断类型转换
# 将RDD中每条数据转换成Row类型,Spark可以自动将RDD转换成DataFrame
# 数据源
userid【用户ID】 movieid【电影ID】 rate【评价】 ts【时间戳】
196 242 3 881250949
186 302 3 891717742
22 377 1 878887116
244 51 2 880606923
196 242 3 881250949
186 302 3 891717742
22 377 1 878887116
244 51 2 880606923
# 实现转换
# step1: 读取数据
# 用RDD方式进行读取
movie_rdd = spark.sparkContext.textFile("../data")
# step2: 处理数据
"""自动推断:RDD中每条数据必须为Row类型,Spark就可以实现自动推断"""
# a.将str类型的RDD变成Row类型的RDD
movie_rdd_row = ( movie_rdd
# 先将每个字符串分割,变成列表
.map(lambda line: re.split("\\s+", line))
# 将每个列表转换成一条Row类型对象数据
.map(lambda item: Row(userid=item[0], movieid=item[1],
rate=float(item[2]), ts=int(item[3])))
)
# b.将RDD转换成DF
movie_df = spark.createDataFrame(movie_rdd_row)
# step3: 保存结果
movie_df.printSchema()
movie_df.show()
自定义Schema转换
# step1: 读取数据
# a.读取数据放入RDD中
move_rdd_str = spark.sparkContext.textFile("../data")
# step2: 处理数据
# b.转换为DataFrame
"""自定义Schema:构建一个元素或者列表类型的RDD,
自定义一个Schema对象StructType,将RDD和Schema对象合并"""
# 先构建元组类型的RDD
movie_rdd_tuple = (move_rdd_str
# 将一行一个字符串转换成一个列表
.map(lambda line: re.split("\\s+", line))
# 将一行一个列表转换成一个元组对象
.map(lambda item: (item[0], item[1], float(item[2]), int(item[3])))
)
# 自定义一个Schema对象
movie_schema = StructType([
StructField(name="userid", dataType=StringType(), nullable=True),
StructField(name="movieid", dataType=StringType(), nullable=True),
StructField(name="rate", dataType=DoubleType(), nullable=True),
StructField(name="ts", dataType=LongType(), nullable=True)
])
# 将RDD和Schema合并,转换为DataFrame
movie_df = spark.createDataFrame(movie_rdd_tuple, movie_schema)
# step3: 保存结果
movie_df.printSchema()
movie_df.show()
指定列名称转换
# toDF函数
# 将元素类型为元组类型的RDD直接转换为DataFrame
# def toDF(self: RDD[RowLike], schema: List[str]) -> DataFrame
# step1: 读取数据
# 用RDD方式进行读取
movie_rdd_str = spark.sparkContext.textFile("../data")
# step2: 处理数据
"""自定义Schema:自己定义RDD中数据对应的Schema"""
# a.将str类型的RDD变成Row类型的RDD
movie_rdd_list = ( movie_rdd_str
# 先将每个字符串分割,变成列表
.map(lambda line: re.split("\\s+", line))
# 将每个列表转换成一条Row类型对象数据
.map(lambda item: (item[0], item[1], float(item[2]), int(item[3])) )
)
# b.将RDD转换成DF
movie_df = movie_rdd_list.toDF(["userid", "movieid", "rate", "ts"])
# step3: 保存结果
movie_df.printSchema()
movie_df.show()
DataFrame的使用
SQL风格
#1.把DF注册为一个视图(表)
createOrReplaceTempView()
#2.写SQL
spark.sql("这里就是写SQL的地方")
DSL风格
(1)SQL中的关键字
(2)RDD算子
(3)pyspark包下,导包的方式:import pyspark.sql.functions as F
# Catalyst优化器
不论是SQL还是DSL,只要计算的逻辑是一样的,经过优化器,最终的实现也是一样的
所以相同执行逻辑的代码性能上没有区别
wordcount案例
# 数据源 word.txt
hadoop hive hadoop hive sqoop
sqoop hive hadoop kafka
sqoop kafka hbase hue
hadoop sqoop oozie
from pyspark.sql import SparkSession
import os
import pyspark.sql.functions as F
# 1.构建SparkSession
# 建造者模式:类名.builder.配置…….getOrCreate()
# 自动帮你构建一个SparkConf对象,只要指定你需要哪些配置就可
#SparkSQL:200
#SparkCore:最终由文件的切片数决定。
#最终调整策略:设置为核心数的2-3倍
spark = SparkSession \
.builder \
.master("local[2]")\
.appName("SparkSQLAppName") \
.config("spark.sql.shuffle.partitions", 4) \
.getOrCreate()
# 2.数据输入
#会把文件内容的每一行当做一个value值
input_df = spark.read.text(paths='../data/word.txt')
# 3.数据处理
#3.1用SQL实现
input_df.createOrReplaceTempView("t1")
result_df1 = spark.sql("""
select word,count(word) as cnt
from
(select explode(split(value,' ')) as word
from t1) t2
group by word
""")
#3.2 用DSL实现
result_df2 = input_df\
.select(F.explode(F.split(input_df['value'],' ')).alias('word'))\
.groupBy("word")\
.count().alias("cnt")
result_df3 = input_df\
.select(F.split('value',' ').alias("words"))\
.select(F.explode('words').alias('word'))\
.groupBy("word")\
.agg(F.count("word").alias('cnt'))
# 4.数据输出
print("-------1.------")
input_df.printSchema()
input_df.show(truncate=False)
print("-------2.------")
result_df1.printSchema()
result_df1.show(truncate=False)
print("-------3.------")
result_df2.printSchema()
result_df2.show(truncate=False)
print("-------4.------")
result_df3.printSchema()
result_df3.show(truncate=False)
# 5.关闭SparkSession
spark.stop()