个人读后小结,如有不对,欢迎批评指正
前言
大概花了一个月(2020-09~2020-10)左右的时间,看完了整本书。笔者毕业后,主要从事机器学习、数据挖掘方向的相关工作。由于Spark作为目前主流的分布式计算引擎,个人也一直在用Spark进行相关的数据分析与建模工作。通读全书,感觉比较适合入门级学习,主要介绍了Spark 2.0相关API及Spark生态。涵盖Spark SQL、Struct Streaming、GraphX、MLlib等内容。对初学者而言是一本不错的书籍。
数据、源码链接: https://github.com/databricks/Spark-The-Definitive-Guide.
第Ⅰ部分 大数据与Spark概述
Spark是加州伯克利分校AMP实验室开发的通用内存计算框架,Spark主要包括Spark SQL(数据分析)、Struct Streaming(流计算)、ML(机器学习)、GraphX(图计算)等组件。使得Spark成为大数据一站式处理平台,在企业项目中得到广泛应用。目前Spark已经进入3.0时代,速度较2.0版本有较大的提升。在可预见的未来,Spark任将是企业进行大数据分析的基石。
第Ⅱ部分 结构化API–DataFrame、SQL和Dataset
结构化API是处理各种数据类型的工具,可处理非结构化的日志文件、半结构化的CSV文件、以及高度结构化的Parquet文件。结构化API主要指以下三种核心分布式集合类型的API:Dataset类型、DataFrame类型、SQL表和视图。
Dataset和DataFrame的比较:
DataFrame是一个分布式的类型为Row的对象集合,Dataset可以使用Java/Scala类定义DataFrame中的每条记录。DataFrame可以看作是Dataset中对象为Row时的特例。Row类型是Spark用于支持内存计算而优化的数据格式。Dataset在编译时检查类型是否符合规范,而DataFrame在运行时检查类型是否与Schema中指定的一致。但Dataset与DataFrame的操作几乎完全一样。
DataFrame的转Dataset:
case class Flight(DEST_COUNTRY_NAME:String,ORIGIN_COUNTRY_NAME:String,count:BigInt)
val flightDF = spark.read.parquet("fileName")
val flights = flights.as[Flight]
RDD、DataFrame、Dataset演变:
DataFrame与RDD相比,更像是传统的二维表,除了记录了表数据,还记录了数据的结构信息:
目前基于RDD的API已经进入了维护阶段,基于DataFrame与Dataset的API今后将成为Spark的核心API。
Spark结构化API执行过程:
- 编写DataFrame、Dataset、SQL代码,
- 如果代码能有效执行,Spark将其转化为一个逻辑执行计划(Logical Plan)
- Spark将此逻辑计划转化成一个物理执行计划(Physical Plan),检查可行的优化策略,并在此检查过程中进行优化
- Spark将生成的不同的物理执行计划,通过代价模型进行比较分析,最终在Spark集群上执行代价最小的物理执行计划(RDD操作)
详细过程见图解:
结构化操作介绍
本文基于伯克利开发的databricks进行操作演示(类似于python 的Jupyter Notebook),仅介绍部分操作,常见的操作不再赘述。数据目录结构如下:
- SQL表达式、DataFrame执行效率:
SQL表达式与DataFrame API代码在执行前会编译成相同的底层逻辑树,这意味着SQL表达式与DataFrame的性能是一样的。个人更倾向于使用DatFrame API。 - select、selectExpr:
select 函数与selectExpr函数支持在DataFrame上使用类SQL查询,可用其操作DataFrame列。selectExpr可以看作是select(expr(…))操作的简化版。其中" * "包含所有原始表中的列。
注意事项:混淆Column对象和字符串,编译报错。
-
字面量(literal):
当需要增加一项常数列时,可采用字面量函数
-
链式过滤
一般为了书写方便,多个过滤条件通常会放在一个表达式中,尽管方式可行,但并不总是有效。因为Spark会同时执行所有过滤条件,不管过滤条件的先后顺序。不过我还是喜欢组合后一起过滤,除非表达式很长,才会拆分成链式过滤。
-
sample、randomSplit
sample函数按一定比例从DataFrame中随机抽取,可以指定是否为放回采样。randomSplit随机切分数据集,机器学习中常用来划分训练集、测试集。
-
null值排序
通过asc_nulls_first、desc_nulls_first指定排序后空值出现的位置
-
sortWithinPartitions
出于性能优化的目的,最好在进行别的转换操作之前,先对每个分区进行内部排序。
-
describe、summary
两者都是输出列的统计信息,summary可输出分位数信息
-
monotonically_increasing_id
为每行添加一个唯一的ID,每个partition内的ID编号连续,分区编号不连续,partition1(0-100),partition2(150-200),partition3(400-500)…
-
regx_replace、translate
两者都可以进行字符串替换
-
var agrs
Spark 可以接受不定量参数,采用var args可以更加简单的处理contains的问题
-
na处理null值
数值型填充时,应注意保持数据类型一致。
-
Struct结构体
spark可以组合多列构成一个结构体
-
数组列
根据某字符串列可生成数组列,供后续explode拆分
-
explode
列主要功能是拆分array_col列中的每个值为一行。同时可以对map_col拆分成key-value两列
-
JSON字符串
Spark可以采用get_json_object解JSON对象,to_json可转化成JSON对象
-
UDF函数
Spark最强大的功能之一就是自定义函数,UDF可以让用户编写自定义转化操作。UDF函数需要在Spark Driver端进行序列化,并将他通过网络传送到worker端。一般来说,避免使用UDF函数是一个很好的优化策略。因为他们强制将数据表示为JVM对象。应该尽可能的使用结构化API来执行操作。 -
window函数
使用window函数可以执行某些特殊的聚类操作。具体指在数据窗口上执行聚合操作。window通常结合rank和dense_rank函数使用。示例如下:
-
rollup、cube分组操作
cube比rollup多了一组col1:null,col2:noNull具体见红色
-
pivot
根据某列中的不同行创建多个列,注意区分groupBy
-
left_semi、left_anti
left_semi(左半连接),实际上并不包含右边DataFrame中的任何值,它只是查看左侧DataFrame的值是否存在于右侧DataFrame,如果存在则在连接结果中保留。left_anti(左反连接),它实际上并不包含右边DataFrame的任何值,只是查看该值左侧DataFrmae的值是否存在于右侧DataFrame,不存在则在连接结果中保留
-
复杂连接
-
shuffle join与broadcast join
Spark以两种不同的方式采取集群间的通信问题,它要么执行all-to-all通信的shuffle join,要么执行broadcast join。当用一个大表连接另一个大表时,最终就是shuffle join。大表与小表间的连接,通常可以将小表广播出去,也就是将较小的DataFrame复制到集群上的所有节点中,听起来很耗时间,但可以避免all-to-all的join,但整体性能要好于all-to-all join。但如果广播的表太大,可能导致driver端节点奔溃。
http://hbasefly.com/2017/03/19/sparksql-basic-join/大表 join 极小表
大表 join 小表
大表 join 大表
-
并行读写数据库
设置numPartitions可以保证在读取和写入数据库时不会导致数据库过载
-
查询下推
谓词下推就是指将各个条件先应用到对应的数据上,而不是根据写入的顺序执行,这样就可以先过滤掉部分数据,降低join等一系列操作的数据量级,提高运算速度。谓词下推(predicate pushdown)属于逻辑优化。优化器可以将谓词过滤下推到数据源,从而使物理执行跳过无关数据。
-
滑动窗口分区.
Spark repatition采用的分区方式是key 的hash分区,可以指定阈值,采用基于阈值范围的滑动窗口分区
-
gzip文件压缩(推荐采用gzip压缩格式的parquet)
gzip相比snappy压缩率更高,df.write.option(“compression”,“gzip”).parquet(path) -
数据划分、数据分桶、maxRecordsPerFile
基于某列对DataFrame进行划分,这使得你在之后读取文件时,可以跳过大量不相关的数据。比如常见的按时间列进行划分,但当某列存在大量不同的数据时,将生成很多小文件。此时,可以考虑数据分桶。maxRecordsPerFile可以限制每个文件的最大记录数,当maxRecordsPerFile与分区数量发生冲突时,以maxRecordsPerFile为准。
第Ⅲ部分 低级API
链接: https://editor.csdn.net/md/?articleId=109321946//未写待续.
第Ⅳ部分 生产与应用
链接: https://editor.csdn.net/md/?articleId=109321946//未写待续.
第Ⅴ部分 流处理
链接: https://editor.csdn.net/md/?articleId=109321946//未写待续.
第Ⅵ部分 高级分析与机器学习
链接: https://editor.csdn.net/md/?articleId=109321946//未写待续.