RDD基本概念

        RDD是弹性分布式数据集,即一个RDD代表一个被分区的只读数据集。一个RDD的生成只有两种途径,一是来自于内存集合和外部存储系统,另一种是通过转换操作来自于其他RDD,比如map、filter、join,等等。

        RDD没必要随时被实例化,由于RDD的接口只支持粗粒度的操作(即一个操作会被应用在RDD的所有数据上),所有只要通过记录下这些作用在RDD之上的转换操作,来构建RDD的继承关系(lineage),就可以有效地进行容错处理,而不需要将实际的RDD数据进行记录拷贝。这对于RDD来说是一项非常强大的功能,也即是在一个Spak程序中,我们所用到的每一个RDD,在丢失或者操作失败后都是
可以重建的。

       应用程序开发者还可以对RDD进行另外两个方面的控制操作:持久化和分区。开发者可以指明他们需要重用哪些RDD,然后选择一种存储策略(如in-memory storage)将它们保存起来。开发者还可以让RDD根据记录中的键值在集群的机器之间重新分区,这对于RDD的位置优化是非常有用的,例如,让将要进行join操作的两个数据集以同样的方式进行哈希分区。
       
        如何表示这样一个分区的、高效容错的而且能够持久化的分布式数据集呢?一般情况下抽象的RDD需要包含下表中所示的五个接口。

                      

 

一. RDD分区

       既然RDD是一个分区的数据集,那么RD肯定具备分区的属性,对于一个RDD而言,分区的多少涉及对这个RDD进行并行计算的粒度,每一个RDD分区的计算操作都在一个单独的任务中被执行。对于RDD的分区而言,用户可以自行指定多少分区,如果没有指定,那么将会使用默认值。可以利用RDD的成员变量partitions所返回的partition数组的大小来查询一个RDD被划分的分区数。

       当然也可以在创建RDD的时候不指定分区,创建出的RDD就采用系统默认的分区数,系统默认的数值是这个程序所分配到的资源的CPU核的个数。

二. RDD优先位置

       RDD优先位置属性与Spark中的调度相关,返回的是此RDD的每个partition所存储的位置,按照“移动数据不如移动计算”的理念,在Spark进行任务调度的时候,尽可能地将任务分配到数据块所存储的位置。

       以从Hadoop中读取数据生成RDD为例,preferredLocations返回每一个数据块所在的机器名或者IP地址,如果每一块数据是多份存储的,那么就会返回多个机器地址,以便后续调度的程序根据这个地址更加有效地分配任务。

 三. RDD依赖关系

        由于RDD是粗粒度的操作数据集,每个转换操作都会生成一个新的RDD.所以RDD之间就会形成类似于流水线一样的前后依赖关系,在Spark中存在两种类型的依赖,即窄依赖和宽依赖。

        窄依赖:每一个父RDD的分区最多只被子RDD的一个分区所使用,如图所示。

                                       
        宽依赖:多个子RDD的分区会依赖于同一个父RDD的分区,如图所示。

                                        

       在图中,一个矩形表示一个RDD,在矩形中的椭圆形表示这个RDD的一个分区,例如,转换操作Map和Filter就会形成一个窄依赖,而没有经过co-partition操作的两个RDD数据集之间进行join操作就会形成宽依赖,在Spark中需要明确地区分这两种依赖关系有两个方面的原因:第一,窄依赖可以在集群的一个节点上如流水线一般地执行,可以计算所有父RDD的分区,相反的,宽依赖需要取得父
RDD的所有分区上的数据进行计算,将会执行类似于MapReduce一样的Shuffle操作。第二,对于窄依赖来说,节点计算失败后的恢复会更加有效,只需要重新计算对应的父RDD的分区,而且可以在其他的节点上并行地计算,相反的,在有宽依赖的继承关系中,一个节点的失败将会导致其父RDD的多个分区重新计算,这个代价是非常高的。

四. RDD分区计算

       对于Spark中每个RDD的计算都是以partition(分区)为单位的,而且RDD中的函数都是在对迭代器进行复合,不需要保存每次计算的结果。在如下程序中,对于rdd变量而言,是一个被分成两个分区的1-10集合,在rdd上连续进行转换操作map和filter,由于compute函数只返回相应分区数据的迭代器,所以只有最终实例化时才能显示出两个分区的最终计算结果.

                         


五. RDD分区函数

       partitioner是RDD分区函数,目前在Spark中实现了两种类型的分区函数,即HashPartitioner(哈希分区)和RangePartitioner(区域分区),且partitioner这个属性只存在于(K,V)类型的RDD中,对于非(K,V)类型的partitioner的值就是None。partitioner函数既决定了RDD本身的分区数量,也可作为其父RDD Shuffle输出(Mapoutput)中每个分区进行数据切割的依据。下面以HashPartitioner来说明partitioner的功能,程序如图所示。

                            

       在程序中,我们首先构造了一个MappedRDD,其partioner的值为None,然后对rdd进行groupbykey操作得出group_rdd变量,对于groupbykey操作而言,这里创建了新的HashPartitioner对象,参数“3”代表了group_rdd最终会拥有三个分区。最后对group_rdd执行collectPartitions行动操作(这个操作仅作为测试用,为了查看每一个分区内的值)。HashPartitioner的工作原理如下图所示。

                                            

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值