RDD分区理解

RDD分区的作用

一个HDFS文件的RDD将文件的每个文件块表示为一个分区,并且知道每个文件块的位置信息。这些对应着数据块的分区分布到集群的节点中,因此,分区的多少涉及对这个RDD进行并行计算的粒度。首先,分区是一个逻辑概念, 变换前后的新旧分区在物理上可能是同一块内存或者是存储。

需要注意的是,如果没有指定分区数将使用默认值,而默认值是该程序所分配到CPU核数,如果是从HDFS文件创建,默认为文件的数据块数。

RDD分区相关的编程接口

移动计算而不移动数据

在Spark形成任务有向无环图时,会尽可能地把计算分配到靠近数据的位置,减少数据的网络传输。当RDD分区被缓存, 则计算应该被发送到缓存分区所在的节点进行,另外,RDD的血统也会影响子RDD的位置,回溯RDD的血统,直到找到具有首选位置属性的父RDD,并据此决定子RDD的位置。

RDD的依赖关系

RDD的依赖分为两种类型,窄依赖和宽依赖。

窄依赖: 每个父RDD的分区都至多被一个子RDD使用,比如map操作就是典型的窄依赖。

宽依赖: 多个子RDD的分区依赖一个父RDD的分区。比如groupByKey都属于宽依赖。

图3-4可以看出join操作在不同的情况下可能是宽依赖也可能是窄依赖。

RDD分区计算

Spark中RDD计算是以分区为单位的,而且计算函数是在对迭代器复合,不需要保留每次计算的结果。

分区计算一般使用mapPartitions等操作进行, mapPartitions的输入函数应用于每个分区,也就是把每个分区中的内容作为整体进行处理。

mapPartitions的函数定义如下:

f 为输入函数,处理每个分区里面的内容,每个分区中的内容以Iterator[T]传递给输入函数f, f的输入结果是Iterator[U]. 而最终的RDD将所有分区经过输入函数处理后的结果合并起来。

RDD分区函数

分区的划分对于shuffle类操作很关键,决定了该操作的父RDD和子RDD的依赖类型。比如之前提到的join操作,如果是协同划分的话,两个父RDD之间, 父RDD与子RDD之间能形成一致的分区安排。即同一个Key保证被映射到同一个分区,这样就是窄依赖。而如果不是协同划分,就会形成宽依赖。所谓的协同划分就是指定分区划分器以产生前后一致的分区安排。

Spark提供两种划分器,HashPartitioner (哈希分区划分器),(RangePartitioner) 范围分区划分器. 需要注意的是分区划分器只存在于PairRDD中,普通非(K,V)类型的Partitioner为None.

可以用下面这种方式指定分区器

其中,4表示groupByKey会有4个分区,以HashPartitioner划分为4个分区。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券