Spark RDD惰性计算的自主优化

原创/朱季谦

RDD(弹性分布式数据集)中的数据就如final定义一般,只可读而无法修改,若要对RDD进行转换或操作,那就需要创建一个新的RDD来保存结果。故而就需要用到转换和行动的算子。

Spark运行是惰性的,在RDD转换阶段,只会记录该转换逻辑而不会执行,只有在遇到行动算子时,才会触发真正的运算,若整个生命周期都没有行动算子,那么RDD的转换代码便不会运行。

这样的惰性计算,其实是有好处的,它在遇到行动算子需要对整个DAG(有向无环图)做优化,以下是一些优化说明——

本文的样本部分内容如下,可以基于这些数据做验证——

Amy Harris,39,男,18561,性价比,家居用品,天猫,微信支付,10,折扣优惠,品牌忠诚
Lori Willis,33,女,14071,功能性,家居用品,苏宁易购,货到付款,1,折扣优惠,日常使用
Jim Williams,61,男,14145,时尚潮流,汽车配件,淘宝,微信支付,3,免费赠品,礼物赠送
Anthony Perez,19,女,11587,时尚潮流,珠宝首饰,拼多多,支付宝,5,免费赠品,商品推荐
Allison Carroll,28,男,18292,环保可持续,美妆护肤,唯品会,信用卡,8,免费赠品,日常使用
Robert Rice,47,男,5347,时尚潮流,图书音像,拼多多,微信支付,8,有优惠券,兴趣爱好
Jason Bradley,25,男,9480,性价比,汽车配件,拼多多,信用卡,5,折扣优惠,促销打折
Joel Small,18,女,15586,社交影响,食品饮料,亚马逊,支付宝,5,无优惠券,日常使用
Stephanie Austin,33,男,7653,舒适度,汽车配件,亚马逊,银联支付,3,无优惠券,跟风购买
Kathy Myers,33,男,18159,舒适度,美妆护肤,亚马逊,货到付款,4,无优惠券,商品推荐
Gabrielle Mccarty,57,男,19561,环保可持续,母婴用品,网易考拉,支付宝,5,免费赠品,日常使用
Joan Smith,43,女,11896,品牌追求,图书音像,亚马逊,支付宝,4,免费赠品,商品推荐
Monica Garcia,19,男,16665,时尚潮流,电子产品,京东,货到付款,7,免费赠品,商品推荐
Christopher Faulkner,55,男,3621,社交影响,美妆护肤,苏宁易购,支付宝,7,无优惠券,日常使用

一、减少不必要的计算

RDD的惰性计算可以通过优化执行计划去避免不必要的计算,同时可以将过滤操作下推到数据源或者其他转换操作之前,减少需要处理的数据量,进而达到计算的优化。

例如,执行以下这段spark代码时,

  def main(args: Array[String]): Unit = {val conf = new SparkConf().setMaster("local[*]").setAppName("count")val ss = SparkSession.builder().config(conf).getOrCreate()val filePath: String = "transaction_data.csv"val lineRDD = ss.sparkContext.textFile(filePath)val value = lineRDD.map { x => {println(s"打印 $x")x.split(",")} }value.take(10).foreach(println)ss.stop()}

若Spark不是惰性计算的情况下,代码顺序运行到这行 val lineRDD = ss.sparkContext.textFile(filePath)代码时,就会将transaction_data.csv文件里的几万条数据全部加载出来,然后再做计算。

而在惰性计算的情况下,直至运行这行代码 value.take(10).foreach(println)而遇到foreach这个行动算子时,才会去执行前面的转换,这时它会基于RDD的转化自行做一个优化——在这个例子里,它会基于lineRDD.take(5)这行代码只会从transaction_data.csv取出前5行,避免了将文件里的几万条数据全部取出。

打印结果如下,发现lineRDD.map确实只处理了前5条数据——

打印 Amy Harris,39,男,18561,性价比,家居用品,天猫,微信支付,10,折扣优惠,品牌忠诚
打印 Lori Willis,33,女,14071,功能性,家居用品,苏宁易购,货到付款,1,折扣优惠,日常使用
打印 Jim Williams,61,男,14145,时尚潮流,汽车配件,淘宝,微信支付,3,免费赠品,礼物赠送
打印 Anthony Perez,19,女,11587,时尚潮流,珠宝首饰,拼多多,支付宝,5,免费赠品,商品推荐
打印 Allison Carroll,28,男,18292,环保可持续,美妆护肤,唯品会,信用卡,8,免费赠品,日常使用
[Ljava.lang.String;@3c87e6b7
[Ljava.lang.String;@77bbadc
[Ljava.lang.String;@3c3a0032
[Ljava.lang.String;@7ceb4478
[Ljava.lang.String;@7fdab70c

二、操作合并和优化

Spark在执行行动算子时,会自动将存在连续转换的RDD操作合并到更为高效的执行计划,这样可以减少中间不是必要的RDD数据的生成和传输,可以整体提高计算的效率。这很像是,摆在你面前是一条弯弯曲曲的道路,但是因为你手里有地图,知道这条路是怎么走的,因此,可以基于这样的地图,去尝试发掘下是否有更好的直径。

还是以一个代码案例说明,假如需要统计薪资在10000以上的人数。

运行的代码,是从transaction_data.csv读取了几万条数据,然后将每行数据按","分割成数组,再基于每个数组去过滤出满足薪资大于10000的数据,最后再做count统计出满足条件的人数。

以下是最冗余的代码,每个步骤都转换生成一个新的RDD,彼此之间是连续的,这些RDD是会占内存空间,同时增加了很多不必要的计算。

def main(args: Array[String]): Unit = {val conf = new SparkConf().setMaster("local[*]").setAppName("count")val ss = SparkSession.builder().config(conf).getOrCreate()val filePath: String = "transaction_data.csv"val lineRDD = ss.sparkContext.textFile(filePath)val array = lineRDD.map(_.split(","))//过滤出薪资10000的数据val valueRdd = array.filter(x => x.apply(3).toInt > 10000)//统计薪资10000以上的人数val count = valueRdd.count()ss.stop()
}

Spark就可能会将这些存在连续的RDD进行优化,将其合并成一个单独的转换操作,直接就对原始RDD进行映射和过滤——

val value = ss.sparkContext.textFile(filePath).map(_.split(",")).filter(x =>{x.apply(3).toInt > 10000})
value.count()

这样优化同时避免了多次循环遍历,每个映射的数组只需要遍历一次即可。

可以通过coalesce(1)只设置一个分区,使代码串行运行,然后增加打印验证一下效果——

val value = ss.sparkContext.textFile(filePath).coalesce(1).map(x =>{println(s"分割打印 $x")x.split(",")
}).filter(x =>{println(s"过滤打印 ${x.apply(0)}")x.apply(3).toInt > 10000})
value.count()

打印部分结果,发现没每遍历一次,就把映射数组和过滤都完成了,没有像先前多个RDD那样需要每次都得遍历,这样就能达到一定优化效果——

分割打印 Amy Harris,39,男,18561,性价比,家居用品,天猫,微信支付,10,折扣优惠,品牌忠诚
过滤打印 Amy Harris
分割打印 Lori Willis,33,女,14071,功能性,家居用品,苏宁易购,货到付款,1,折扣优惠,日常使用
过滤打印 Lori Willis
分割打印 Jim Williams,61,男,14145,时尚潮流,汽车配件,淘宝,微信支付,3,免费赠品,礼物赠送
过滤打印 Jim Williams
分割打印 Anthony Perez,19,女,11587,时尚潮流,珠宝首饰,拼多多,支付宝,5,免费赠品,商品推荐
过滤打印 Anthony Perez
分割打印 Allison Carroll,28,男,18292,环保可持续,美妆护肤,唯品会,信用卡,8,免费赠品,日常使用
过滤打印 Allison Carroll
分割打印 Robert Rice,47,男,5347,时尚潮流,图书音像,拼多多,微信支付,8,有优惠券,兴趣爱好
过滤打印 Robert Rice

这样也提醒了我们,在遇到连续转换的RDD时,其实可以自行做代码优化,避免产生中间可优化的RDD和遍历操作。

三、窄依赖优化

RDD在执行惰性计算时,会尽可能进行窄依赖优化。

有窄依赖,便会有宽依赖,两者有什么区别呢?

窄依赖指的是父RDD的每个分区只需要通过简单的转换操作就可以计算出对应的子RDD分区,不涉及跨多个分区的数据交换,即父子之间每个分区都是一对一的。

前文提到的map、filter等转换都属于窄依赖的操作。

例如,array.filter(x => x.apply(3).toInt > 10000),父RDD有三个分区,那么三个分区就会分别执行array.filter(x => x.apply(3).toInt > 10000)将过滤的数据传给子RDD对应的分区——

image

宽依赖指父RDD的每个分区会通过跨区计算将原本同一个分区数据分发到不同子分区上,这中间涉及到shuffle重新洗牌操作,会存在较大的计算,父子之间分区是一对多的。可以看到,父RDD同一个分区的数据,在宽依赖情况下,会将相同的key传输到同一个分区里,这就意味着,同一个父RDD,如果存在多个不同的key,可能会分发到多个不同的子分区上,进而出现shuffle重新洗牌操作。

image

因此,RDD会尽可能的进行窄依赖优化,在无需跨区计算的情况下,就避免进行shuffle重新洗牌操作,将父分区一对一地传输给子分区。同时,窄依赖还有一个好处是,在子分区出现丢失数据异常时,只需要重新计算对应的父分区数据即可,无需将父分区全部数据进行计算。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/205692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python】Python仓储管理系统(源码)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

uni-app 微信小程序之好看的ui登录页面(二)

文章目录 1. 页面效果2. 页面样式代码 更多登录ui页面 uni-app 微信小程序之好看的ui登录页面(一) uni-app 微信小程序之好看的ui登录页面(二) uni-app 微信小程序之好看的ui登录页面(三) uni-app 微信小程…

go的两大测试方法- 官网推荐

go的两大测试方法- 官网推荐 go的两大测试方法- 官网推荐常见的不正规测试方法main方法个例测试验证 - 不正规1. 提供一个函数:Reverse(input string)进行测试2. 直接在函数下创建main函数下进行个例测试3. 测试发现,Reverse方法不支持某些汉字&#xff…

【SQL开发实战技巧】系列(四十九):Oracle12C常用新特性☞表分区部分索引(Partial Indexes)

系列文章目录 【SQL开发实战技巧】系列(一):关于SQL不得不说的那些事 【SQL开发实战技巧】系列(二):简单单表查询 【SQL开发实战技巧】系列(三):SQL排序的那些事 【SQL开发实战技巧…

数据分析基础之《matplotlib(4)—柱状图》

一、柱状图绘制 1、柱状图要素 有类别 2、需求:对比每部电影的票房收入 电影数据如下图所示: 3、matplotlib.pyplot.bar(x, height, width0.8, bottomNone, *, aligncenter, dataNone, **kwargs) 说明: x:有几个类别 height&am…

玩转Sass:掌握数据类型!

当我们在进行前端开发的时候,有时候需要使用一些不同的数据类型来处理样式,Sass 提供的这些数据类型可以帮助我们更高效地进行样式开发,本篇文章将为您详细介绍 Sass 中的数据类型。 布尔类型 在 Sass 中,布尔数据类型可以表示逻…

每日一练:插入排序

1. 概念及原理 插入排序是一种简单直观的排序算法,其基本思想是将一个元素插入到已经排序好的部分,然后不断地重复这个过程,直到整个数组有序。下面是插入排序的算法原理: 初始状态: 数组被分为已排序和未排序两个部分…

Qt::UniqueConnection和lambda一块用无效

如果槽函数是lambda。 那么用了Qt::UniqueConnection也会出现槽函数被多次调用的问题。 原因: 参考官方文档: QObject Class | Qt Core 5.15.16https://doc.qt.io/qt-5/qobject.html#connect

k8s-service 7

由控制器来完成集群的工作负载,service(微服务)是将工作负载的应用暴露出去,从而解决访问问题 作用:无论是在集群内还是集群外,都可以访问pod上的应用,其实现对集群内的应用pod自动发现和负载均…

jQuery ajax读取本地json文件 三级联动下拉框

步骤 1:创建本地JSON文件 {"departments": [{"name": "会计学院","code": "052"},{"name": "金融学院","code": "053"},{"name": "财税学院",&qu…

【c】小红的漂亮串

#include<stdio.h> #include<string.h> int main() {char arr[1000];int count0;gets(arr);//在数组中输入字符串int lenstrlen(arr);//求字符串长度printf("%d\n",len);for(int i0;i<len;i){if(arr[i]r){if(arr[i1]e){if(arr[i2]d){countcount1;}}}}…

ChatGPT可能即将发布新版本,带有debug功能:支持下载原始对话、可视化对话分支等

本文原文来自DataLearnerAI官方网站&#xff1a;ChatGPT内置隐藏debug功能&#xff1a;支持下载原始对话、可视化对话分支等 | 数据学习者官方网站(Datalearner) AIPRM的工作人员最近发现ChatGPT的客户端隐藏内置了一个新的debug特性&#xff0c;可以提高ChatGPT对话的问题调试…

AZURE==SQL managed instances

创建资源 创建DB 创建完成后&#xff0c;拿着刚才的账号密码依然连接不上 远程连接 需要开启公网访问和开放相关端口 参考Configure public endpoint - Azure SQL Managed Instance | Microsoft Learn 连接成功

Python源码分享10:使用海龟画图turtle画哆啦A梦

turtle模块是一个Python的标准库之一&#xff0c;它提供了一个基于Turtle graphics的绘图库。Turtle graphics是一种流行的绘图方式&#xff0c;它通过控制一个小海龟在屏幕上移动来绘制图形。 turtle模块可以让您轻松地创建和控制海龟图形&#xff0c;从而帮助您学习Python编…

使用xshell连接虚拟机(服务器)

作者&#xff1a;余小小 Xshell Xshell [1] 是一个强大的安全终端模拟软件&#xff0c;它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议。Xshell 通过互联网到远程主机的安全连接以及它创新性的设计和特色帮助用户在复杂的网络环境中享受他们的工作。 Xshell可以…

SpringDataJPA基础

简介 Spring Data为数据访问层提供了熟悉且一致的Spring编程模版&#xff0c;对于每种持久性存储&#xff0c;业务代码通常需要提供不同存储库提供对不同CURD持久化操作。Spring Data为这些持久性存储以及特定实现提供了通用的接口和模版。其目的是统一简化对不同类型持久性存储…

华清远见嵌入式学习——QT——作业1

作业要求&#xff1a; 代码&#xff1a; ①&#xff1a;头文件 #ifndef LOGIN_H #define LOGIN_H#include <QWidget> #include <QLineEdit> //行编辑器类 #include <QPushButton> //按钮类 #include <QLabel> //标签类 #include <QM…

图像处理之把模糊的图片变清晰

1.图片如果是有雾化效果的对图像产生影响的,要先进行图形增强,Retinex是基于深度神经网络了,我在之前图形处理的文章一路从神经网络(概率统计)—>积卷神经网络(对区域进行概率统计,对图片进行切割多个识别对象)–>深度积卷神经网络(RetinexNet也是模拟人脑的处理过程,增加…

css弹窗动画效果,示例弹窗从底部弹出

从底部弹出来&#xff0c;有过渡动画效果 用max-height可以自适应内容的高度&#xff0c;当内容会超过最大高度时可以在弹窗里加个scroll-view 弹窗不能用v-if来隐藏&#xff0c;不然transition没效果&#xff0c;transition只能对已有dom元素起效果&#xff0c;所以用透明和v…

软件测试入门:静态测试

什么是静态测试 顾名思义&#xff0c;这里的静态是指程序的状态&#xff0c;即在不执行代码的情况下检查软件应用程序中的缺陷。进行静态测试是为了仅早在开发的早期阶段发现程序缺陷&#xff0c;因为这样可以更快速地识别缺陷并低成本解决缺陷&#xff0c;它还有助于查找动态测…