#博学谷IT学习技术支持#
第一章 快速入门
1.1 什么是SparkSQL
SparkSQL 是Spark的一个模块, 用于处理海量结构化数据
第一、针对结构化数据处理,属于Spark框架一个部分
第二、抽象数据结构:DataFrame
DataFrame = RDD + Schema信息;
第三、分布式SQL引擎,类似Hive框架
从Hive框架继承而来,Hive中提供bin/hive交互式SQL命令行及HiveServer2服务,SparkSQL都可以;
Spark SQL模块架构示意图如下
备注:Catalog就是Spark 2.0之后提供的访问元数据的类:Catalog提供一些API用来对数据库、表、视图、缓存、列、函数(UDF/UDAF)进行操作
1.2 为什么要学习SparkSQL
由于MapReduce这种计算模型执行效率比较慢,rdd原生代码较为复杂,所以Spark SQL应运而生,它是将Spark SQL转换成RDD,然后提交到集群中去运行,执行效率非常快!(查看官网学习)
SparkSQL是非常成熟的 海量结构化数据处理框架.
学习SparkSQL主要在2个点:
SparkSQL本身十分优秀, 支持SQL语言\性能强\可以自动优化\API简单\兼容HIVE等等
企业大面积在使用SparkSQL处理业务数据
离线开发
数仓搭建
科学计算、数据分析
1.3 SparkSQL特点
1)用户接口:Client
CLI(command-line interface)、JDBC/ODBC(jdbc 访问 hive)、WEBUI(浏览器访问 hive)
2)元数据:Metastore
元数据包括:表名、表所属的数据库(默认是 default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;
默认存储在自带的 derby 数据库中,推荐使用 MySQL 存储 Metastore
3)Hadoop
使用 HDFS 进行存储,使用 MapReduce 进行计算。
4)驱动器:Driver
5)解析器(SQL Parser)
将 SQL 字符串转换成抽象语法树 AST,这一步一般都用第三方工具库完成,比如 antlr;
对 AST 进行语法分析,比如表是否存在、字段是否存在、SQL 语义是否有误。
6)编译器(Physical Plan)
将 AST 编译生成逻辑执行计划。
7)优化器(Query Optimizer)
对逻辑执行计划进行优化。
8)执行器(Execution)
把逻辑执行计划转换成可以运行的物理计划。对于 Hive 来说,就是 MR/Spark。
1.4 SparkSQL发展历史
Hive架构回顾
HQL 转换为 MR 任务流程说明
1.进入程序,利用Antlr框架定义HQL的语法规则,对HQL完成词法语法解析,将HQL转换为为AST(抽象语法树);
2.遍历AST,抽象出查询的基本组成单元QueryBlock(查询块),可以理解为最小的查询执行单元;
3.遍历QueryBlock,将其转换为OperatorTree(操作树,也就是逻辑执行计划),可以理解为不可拆分的一个逻辑执行单元;
4.使用逻辑优化器对OperatorTree(操作树)进行逻辑优化。例如合并不必要的ReduceSinkOperator,减少Shuffle数据量;
5.遍历OperatorTree,转换为TaskTree。也就是翻译为MR任务的流程,将逻辑执行计划转换为物理执行计划;
6.使用物理优化器对TaskTree进行物理优化;
7.生成最终的执行计划,提交任务到Hadoop集群运行。
Hive
可以发现Hive框架底层就是MapReduce,所以在Hive中执行SQL时,往往很慢很慢
Spark出现以后,将HiveQL语句翻译成基于RDD操作,此时Shark框架诞生了。
- 前身 Shark框架
Shark即Hive on Spark,本质上是通过Hive的HQL进行解析,把HQL翻译成Spark上对应的RDD操作,然后通过Hive的Metadata获取数据库里表的信息,实际为HDFS上的数据和文件,最后有Shark获取并放到Spark上计算。
但是Shark框架更多是对Hive的改造,替换了Hive的物理执行引擎,使之有一个较快的处理速度。然而不容忽视的是Shark继承了大量的Hive代码,因此给优化和维护带来大量的麻烦。为了更好的发展,Databricks在2014年7月1日Spark Summit上宣布终止对Shark的开发,将重点放到SparkSQL模块上。
SparkSQL模块主要将以前依赖Hive框架代码实现的功能自己实现,称为Catalyst引擎。
第二章 SparkSQL概述
2.1 SparkSQL和Hive的异同
Hive和Spark 均是:“分布式SQL计算引擎”
均是构建大规模结构化数据计算的绝佳利器,同时SparkSQL拥有更好的性能。
目前,企业中使用Hive仍旧居多,但SparkSQL将会在很近的未来替代Hive成为分布式SQL计算市场的顶级
2.2 SparkSQL的数据抽象
回顾Pandas和SparkSQL的数据抽象
Pandas - DataFrame
二维表数据结构
单机(本地)集合
SparkCore - RDD
无标准数据结构,存储什么数据均可
分布式集合(分区)
Pandas - DataFrame
•二维表数据结构
•单机(本地)集合
SparkCore - RDD
•无标准数据结构,存储什么数据均可
•分布式集合(分区)
SparkSQL - DataFrame
•二维表数据结构
•分布式集合(分区)
SparkSQL 其实有3类数据抽象对象
SchemaRDD对象(已废弃)
DataSet对象:可用于Java、Scala语言
DataFrame对象:可用于Java、Scala、Python、R
我们以Python开发SparkSQL,主要使用的就是DataFrame对象作为核心数据结构
在SparkSQL当中,Spark为我们提供了两个操作SparkSQL的抽象,分别是DataFrame和DataSet。也就是说我们操作SparkSQL一般都是使用DataFrame或者DataSet来实现的
RDD(Spark1.0) ==> DataFrame(1.3) ==> DataSet(1.6)
2.3 SparkSQL数据抽象的发展
RDD
RDD是一个懒执行的不可变的可以支持Lambda表达式的并行数据集合。
RDD的最大好处就是简单,API的人性化程度很高。
RDD的劣势是性能限制,它是一个JVM驻内存对象,这也就决定了存在GC的限制和数据增加时Java序列化成本的升高。
DataFrame
什么是DataFrame
DataFrame的前身是SchemaRDD,从Spark 1.3.0开始SchemaRDD更名为DataFrame。并不再直接继承自RDD,而是自己实现了RDD的绝大多数功能。
DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库的二维表格,带有Schema元信息(可以理解为数据库的列名和类型)
总结:
DataFrame ==> RDD - 泛型 + Schema + 方便的SQL操作 + 优化
DataFrame是特殊的RDD
DataFrame是一个分布式的表
RDD、DataFrame、DataSet的区别
RDD[Person]
以Person为类型参数,但不了解 其内部结构。
DataFrame
DataFrame = RDD[Person] - 泛型 + Schema + SQL操作 + 优化
提供了详细的结构信息schema列的名称和类型。这样看起来就像一张表了
DataSet[Person]
DataFrame = RDD[Person] - 泛型 + Schema + SQL操作 + 优化
不光有schema信息,还有类型信息
注意:DataFrame = DataSet[Row]
2.4 SparkSession 应用入口 SparkSession对象
在RDD阶段,程序的执行入口对象是: SparkContext
在Spark 2.0后,推出了SparkSession对象,作为Spark编码的统一入口对象。
SparkSession对象可以:
l- 用于SparkSQL编程作为入口对象
l- 用于SparkCore编程,可以通过SparkSession对象中获取到SparkContext
所以,我们后续的代码,执行环境入口对象,统一变更为SparkSession对象
SparkSession:这是一个新入口,取代了原本的SQLContext与HiveContext。对于DataFrame API的用户来说,Spark常见的混乱源头来自于使用哪个“context”。现在使用SparkSession,它作为单个入口可以兼容两者,注意原本的SQLContext与HiveContext仍然保留,以支持向下兼容。
文档:
http://spark.apache.org/docs/latest/sql-getting-started.html
1)、SparkSession在SparkSQL模块中
2)、SparkSession对象实例通过建造者模式构建
SparkSession实现了SQLContext及HiveContext所有功能。SparkSession支持从不同的数据源加载数据,并把数据转换成DataFrame,并且支持把DataFrame转换成SQLContext自身中的表,然后使用SQL语句来操作数据。SparkSession亦提供了HiveQL以及其他依赖于Hive的功能的支持。
其中①表示导入SparkSession所在的包,②表示建造者模式构建对象和设置属性
构建SparkSession核心代码
# coding:utf8
# SparkSQL 中的入口对象是SparkSession对象
from pyspark.sql import SparkSession
if __name__ == '__main__':
# 构建SparkSession对象, 这个对象是 构建器模式 通过builder方法来构建
spark = SparkSession.builder.\
appName("local[*]").\
config("spark.sql.shuffle.partitions", "4").\
getOrCreate()
# appName 设置程序名称, config设置一些常用属性
# 最后通过getOrCreate()方法 创建SparkSession对象
from pyspark.sql import SparkSession
from pyspark.sql import Row
import os
os.environ['SPARK_HOME'] = '/export/servers/spark'
PYSPARK_PYTHON = "/root/anaconda3/envs/pyspark_env/bin/python"
# 当存在多个版本时,不指定很可能会导致出错
os.environ["PYSPARK_PYTHON"] = PYSPARK_PYTHON
os.environ["PYSPARK_DRIVER_PYTHON"] = PYSPARK_PYTHON
if __name__ == '__main__':
# TODO: 构建SparkSession实例对象,读取数据
# 设置应用名称和运行模式
# 通过装饰模式获取实例对象,此种方式为线程安全的
spark = SparkSession.builder\
.appName('test')\
.getOrCreate()
sc = spark.sparkContext
# spark.conf.set("spark.sql.shuffle.partitions", 6)
# TODO: 2. 从文件系统读取数据,包含本地文件系统或HDFS文件系统
inputDS = spark.read.text("file:///export/pyfolder1/pyspark-chapter03_3.8/data/word.txt")
print(type(inputDS))
print("Count={}".format(inputDS.count()))
inputDS.show()
spark.stop()
第三章 DataFrame入门和操作
3.1 DataFrame概述
DataFrame和RDD都是:弹性的、分布式的、数据集
只是,DataFrame存储的数据结构“限定”为:二维表结构化数据
而RDD可以存储的数据则没有任何限制,想处理什么就处理什么
DataFrame 是按照二维表格的形式存储数据
RDD则是存储对象本身
3.2 DataFrame初体验
范例演示:加载json格式数据
第一步、上传官方测试数据$SPARK_HOME/examples/src/main/resources至HDFS目录/datas
第二步、启动pyspark-shell命令行,采用本地模式localmode运行
第三步、读取雇员信息数据
3.3 Schema 信息详解
查看DataFrame中Schema是什么,执行如下命令:
可以看出Schema信息封装在StructType中,包含很多StructField对象,查看源码。
其一、StructType 定义,是一个样例类,属性为StructField的数组
其二、StructField 定义,同样是一个样例类,有四个属性,其中字段名称和类型为必填
自定义Schema结构,官方提供实例代码:
3.4 Row对象
DataFrame中每条数据封装在Row中,Row表示每行数据,具体哪些字段位置,获取DataFrame中第一条数据。
如何构建Row对象:传递value即可,官方实例代码:
from pyspark.sql import Row
// Create a Row from values.
Row(value1, value2, value3, ...)
如何获取Row中每个字段的值呢?
下标获取,从0开始,类似数组下标获取
Row对象构建Dataframe部分代码演示
peopleDF.filter((peopleDF.age >= 19) & (peopleDF.age <= 28)).show()
peopleDF.filter("age>= 19 and age <=28").show()
# 尝试一下操作
from pyspark.sql.functions import col, when
peopleDF.withColumn("little",when((col("age") >= 19) & (col("age") <= 28),1).otherwise(0)).show()
peopleDF.select("age",(when((peopleDF["age"]>=19)& (peopleDF["age"]<=28),1).otherwise(0)).alias("xxx")).show()
if __name__ == '__main__':
spark = SparkSession.builder \
.appName('test') \
.getOrCreate()
sc = spark.sparkContext
# Load a text file and convert each line to a Row.
# 读取一个文件转化每一行为Row对象
lines = sc.textFile("file:///export/pyfolder1/pyspark-chapter03_3.8/data/sql/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 = spark.createDataFrame(people)
schemaPeople.createOrReplaceTempView("people")
# SQL 可以在已注册为表的 DataFrame 上运行。
teenagers = spark.sql("SELECT name FROM people WHERE age >= 13 AND age <= 19")
teenNames = teenagers.rdd.map(lambda p: "Name: " + p.name).collect()
for name in teenNames:
print(name)# Name: Justin
spark.stop()