首页 > 编程知识 正文

在spark中常用的rdd有哪些,rdd窄依赖算子

时间:2023-05-03 15:36:48 阅读:111002 作者:2167

1.RDD之间的依赖关系引线

讨论RDD之间的依赖关系

然后讨论RDD分区之间的关系

最后确定RDD之间依赖关系的分类

完善案例逻辑关系图

什么是RDD之间的依赖关系?

什么是关系(依赖关系)?

从运营商的角度来看,splitRDD通过map运营商得到了tupleRDD,所以splitRDD和tupleRDD的关系是map

但是,只有这样是不够的。 仔细看,RDD只是数据和关于数据的计算。 具体执行这个计算得到的是神秘的其他组件。 因此,这两个RDD之间的关系可以表示为,splitRDD中的数据通过映射操作传递到tupleRDD,这是一种更细化的关系

然而,因为RDD概念本身不是数据容器,且数据实际要存储的位置是RDD上的一个分区,所以若将视点放在数据这一级上,直接说这两个RDD之间存在关系是不科学的。

这些分区之间有什么关系?

仅从splitRDD和tupleRDD之间来说,分区之间是一对一的关系

但是从tupleRDD到reduceRDD呢? tupleRDD通过操作符reduceByKey (一个Shuffle操作)生成reduceRDD。 Shuffle操作中的两个RDD分区之间不是一对一的,reduceByKey中的一个分区对应于tupleRDD中的多个分区

reduceByKey操作符生成ShuffledRDD

reduceByKey由运算符combineByKey实现,在combineByKey内部创建ShuffledRDD返回。 具体代码请在IDEA上确认。 这里不显示屏幕快照,但整个reduceByKey操作大致如下所示

卸下reducer端的两个分区,只留下一个,如下所示

因此,对于reduceByKey这个Shuffle操作来说,reducer端的一个分区将从多个映射端的分区获取数据,是多对一的关系

到目前为止,出现了一对一和多对一两种区划的关系

整体流程图

2 .详细读取rdd之间的相关性

在前一节中,以RDD的分区间的关系有两种形式为例进行了说明

一对一,一般直接变换

多对一,一般是Shuffle

本节讨论以下问题:

如果分区之间的关系是一对一或多对一的,那么这种情况下RDD之间的关系的正式名称是什么呢?

RDD之间的依赖关系具体有几种情况吗?

狭隘的依赖

假设RDDB=RDDA.transform(… (. ),如果rddb中的一个分区依赖于rdda,即父rdd中的少数分区,则将rdd之间的依赖关系称为窄依赖关系

换句话说,子RDD的每个分区依赖于父RDD的少数分区,这种依赖关系称为狭窄依赖关系

提高警惕

valsc=. valr DDA=sc.parallelize (seq (1,2,3 ) (valrddb=sc.parallelize ) seq ) (a,)、(b ) ) ) * )执行结果3333333 2 b ) *.rdda.cartesian(rddb ).collect ).foreach ) println ) _ )上述代码中的cartesian是用于确定两个集合的直积

以上代码的执行结果将合并RDDA中的每个元素和rddB中的所有元素,最终结果数为两个rdd数之和

RDDC有两个父rdd:rdda和rddB

对于cartesian来说,依赖关系如下

上述图表清楚地显示了以下现象

RDDC的分区数是两个父rdd的分区数的乘积

rddA中的每个分区对应于rddC中的两个分区,而rddB中的每个分区对应于rddC中的三个分区。 因为rddA有三个分区

它们之间是狭窄的依赖关系,为什么实际上在cartesian中也是名为NarrowDependency的所有狭窄依赖关系的父类的唯一直接使用呢?

因为所有的分区之间是拷贝关系, 并不是 Shuffle 关系

RDDC中的每个分区并不依赖于多个父rdd中的多个分区

RDDC中每个分区的数量来自父rdd分区中的所有数据,为FullDepen

dence, 所以数据可以直接从父 RDD 流动到子 RDD

不存在一个父 RDD 中一部分数据分发过去, 另一部分分发给其它的 RDD

宽依赖

 

并没有所谓的宽依赖, 宽依赖应该称作为 ShuffleDependency

在 ShuffleDependency 的类声明上如下写到

Represents a dependency on the output of a shuffle stage.

上面非常清楚的说道, 宽依赖就是 Shuffle 中的依赖关系, 换句话说, 只有 Shuffle 产生的地方才是宽依赖

那么宽窄依赖的判断依据就非常简单明确了, 是否有 Shuffle ?

举个 reduceByKey 的例子, rddB = rddA.reduceByKey( (curr, agg) ⇒ curr + agg ) 会产生如下的依赖关系

rddB 的每个分区都几乎依赖 rddA 的所有分区

对于 rddA 中的一个分区来说, 其将一部分分发给 rddB 的 p1, 另外一部分分发给 rddB 的 p2, 这不是数据流动, 而是分发

如何分辨宽窄依赖 ?

其实分辨宽窄依赖的本身就是在分辨父子 RDD 之间是否有 Shuffle, 大致有以下的方法

如果是 Shuffle, 两个 RDD 的分区之间不是单纯的数据流动, 而是分发和复制

一般 Shuffle 的子 RDD 的每个分区会依赖父 RDD 的多个分区

但是这样判断其实不准确, 如果想分辨某个算子是否是窄依赖, 或者是否是宽依赖, 则还是要取决于具体的算子, 例如想看 cartesian 生成的是宽依赖还是窄依赖, 可以通过如下步骤

查看 map 算子生成的 RDD

进去 RDD 查看 getDependence 方法

总结

RDD 的逻辑图本质上是对于计算过程的表达, 例如数据从哪来, 经历了哪些步骤的计算

每一个步骤都对应一个 RDD, 因为数据处理的情况不同, RDD 之间的依赖关系又分为窄依赖和宽依赖 *

3. 常见的窄依赖类型

导读

常见的窄依赖其实也是有分类的, 而且宽窄以来不太容易分辨, 所以通过本章, 帮助同学明确窄依赖的类型

一对一窄依赖

其实 RDD 中默认的是 OneToOneDependency, 后被不同的 RDD 子类指定为其它的依赖类型, 常见的一对一依赖是 map 算子所产生的依赖, 例如 rddB = rddA.map(…​)

每个分区之间一一对应, 所以叫做一对一窄依赖

Range 窄依赖

Range 窄依赖其实也是一对一窄依赖, 但是保留了中间的分隔信息, 可以通过某个分区获取其父分区, 目前只有一个算子生成这种窄依赖, 就是 union 算子, 例如 rddC = rddA.union(rddB)

rddC 其实就是 rddA 拼接 rddB 生成的, 所以 rddC 的 p5 和 p6 就是 rddB 的 p1 和 p2

所以需要有方式获取到 rddC 的 p5 其父分区是谁, 于是就需要记录一下边界, 其它部分和一对一窄依赖一样

多对一窄依赖

多对一窄依赖其图形和 Shuffle 依赖非常相似, 所以在遇到的时候, 要注意其 RDD 之间是否有 Shuffle 过程, 比较容易让人困惑, 常见的多对一依赖就是重分区算子 coalesce, 例如 rddB = rddA.coalesce(2, shuffle = false), 但同时也要注意, 如果 shuffle = true 那就是完全不同的情况了

因为没有 Shuffle, 所以这是一个窄依赖

再谈宽窄依赖的区别

宽窄依赖的区别非常重要, 因为涉及了一件非常重要的事情: 如何计算 RDD ?

宽窄以来的核心区别是: 窄依赖的 RDD 可以放在一个 Task 中运行

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。