阿飞飞飞

学而时习之

导航

RDD——弹性分布式数据集

RDD是将数据项拆分为多个分区的集合,储存在集群的工作节点上的内存和磁盘上,RDD是用于数据转换的接口,其不存实际数据内容

RDD的特点:

弹性:RDD默认存放在内存中,当内存不足时,Spark自动将RDD写入磁盘

容错性:根据数据血统,可以自动从节点失败中恢复分区

分布式数据集:RDD为只读的分区记录集合,每个分区分布在不同节点上

 

RDD的分区特点决定它属于分布式数据集

分区越多,则得到的并行性就越强;

每个分区都是被分发到不同的worker node的候选者

每一个分区对应一个task

 

关于RDD的分区方式,可以分为以下三种:

默认的情况下,为范围分区

 val conf = new SparkConf().setMaster("local[8]").setAppName("job")
 val sc = new SparkContext(conf)
 val rdd = sc.parallelize(List(1,2,3,4,5,6,7,8),2)
 //范围分区
 rdd.foreachPartition(x=>println(x.toList))
//List(1, 2, 3, 4)
   List(5, 6, 7, 8)

当需要使用Hash分区时,RDD内的数据类型必须为键值对,同时需要调用grouyBy或reduceByKey方法

//类型为键值对,但仍属于范围分区
    rdd.map((_,1)).foreachPartition(x=>println(x.toList))
    //List((5,1), (6,1), (7,1), (8,1))
      List((1,1), (2,1), (3,1), (4,1))

//Hash分区
    rdd.map((_,1)).groupByKey(2).foreachPartition(x=>println(x.toList))
    //List((1,CompactBuffer(1)), (3,CompactBuffer(1)), (7,CompactBuffer(1)), (5,CompactBuffer(1)))
      List((4,CompactBuffer(1)), (6,CompactBuffer(1)), (8,CompactBuffer(1)), (2,CompactBuffer(1)))

自定义分区方式

//对于自定义的分区,需要继承Partitioner
//自定义方法如下:
class MyPartition(numPartition:Int) extends Partitioner{
  override def numPartitions: Int = {
    numPartition
  }

  override def getPartition(key: Any): Int = {
    if (key.asInstanceOf[Int]<3) 0
    else if (key.asInstanceOf[Int]>=6) 1
    else 2
  }
}

//自定义分区
    rdd.map((_,1)).partitionBy(new MyPartition(3)).foreachPartition(x=>println(x.toList))
    //List((6,1), (7,1), (8,1))
      List((3,1), (4,1), (5,1))
      List((1,1), (2,1))

 

对于已经定义了分区方式的RDD,也可以重新进行分区,调用方法 repartition()或coalesce(),其中repartition是coalesce接口中shuffle为true的实现

假设源RDD分区为N,现在重新分区需要M

当N<M时,即重新定义的分区数变多,通常使用方法repartition,因为其默认为shuffle为true的实现,若是调用coalesce(N,false),不经过shuffle,是无法将RDD的分区数变多

当N>M时且数量级相近,可以将N个分区的若干分区合并为一个新的分区,最终为M个,这时可以将shuffle设置为false,能有效提高效率

当N>M且数量级相差较大时,当进程数<=分区数,coalesce效率高,为了有更好的并行度,可以将shuffle设置为true

posted on 2020-09-22 19:54  阿飞飞飞  阅读(313)  评论(0编辑  收藏  举报