• spark RDD


    RDD

    RDD是Resilient Distributed Dataset的英文缩写,是spark的基本数据抽象,代表着一个不可变的、多分区的、可并行操作的元素集合。

    RDD有5个主要属性:

    • 分区列表 (partition list)
    • 计算某个分区函数(compute)
    • 依赖列表 (dependency list)
    • kv类型RDD的分区器(可选的)
    • 计算某个分区最优位置的函数(可选的)
    abstract class RDD[T: ClassTag](
        @transient private var _sc: SparkContext,
        @transient private var deps: Seq[Dependency[_]]
      ) extends Serializable with Logging {
      
      def compute(split: Partition, context: TaskContext): Iterator[T]
    
      protected def getPartitions: Array[Partition]
    
      protected def getDependencies: Seq[Dependency[_]] = deps
    
      protected def getPreferredLocations(split: Partition): Seq[String] = Nil
    
      @transient val partitioner: Option[Partitioner] = None
      
      def this(@transient oneParent: RDD[_]) =
        this(oneParent.context, List(new OneToOneDependency(oneParent)))
    

    可见血统关系是通过deps依赖列表来保存的,如果不指定依赖列表则默认创建一对一的依赖关系OneToOneDependency

    函数注入

    RDD类中定义了一些通用的转换函数如map``fliter``union等同时RDD的伴生对象中通过隐式转换的方式定义了一些额外的转换函数,比如kv类型的RDD一些转换函数:groupByKey cogroup

      implicit def rddToPairRDDFunctions[K, V](rdd: RDD[(K, V)])
        (implicit kt: ClassTag[K], vt: ClassTag[V], ord: Ordering[K] = null): PairRDDFunctions[K, V] = {
        new PairRDDFunctions(rdd)
      }
    
    

    依赖关系

    Dependency抽象类来描述依赖关系,有两种子类:

    • NarrowDependency 这也就是常说的窄依赖,子RDD的每一个分区依赖固定个父RDD的分区。这种依赖关系是固定的可以通过def getParents(partitionId: Int): Seq[Int]函数计算出子RDD的某个分区依赖的父RDD的分区。
    • ShuffleDependency 也就是常说的宽依赖,这种依赖关系会触发shuffle,也是spark任务划分stage的标准。

    具体实现

    • MapPartitionsRDD 不创建新的分区列表,采用一对一的依赖关系,每个分区的计算就是在对应父分区上运用传入的转换函数。
      override val partitioner = if (preservesPartitioning) firstParent[T].partitioner else None
    
      override def getPartitions: Array[Partition] = firstParent[T].partitions
    
      override def compute(split: Partition, context: TaskContext): Iterator[U] =
        f(context, split.index, firstParent[T].iterator(split, context) 
    
    • ParallelCollectionRDD 作为source类型的RDD,依赖列表为空,会根据传入的数据和并行度计算新的分区列表,用ParallelCollectionPartition对象保存每个分区的数据。
      override def getPartitions: Array[Partition] = {
        val slices = ParallelCollectionRDD.slice(data, numSlices).toArray
        slices.indices.map(i => new ParallelCollectionPartition(id, i, slices(i))).toArray
      }
    
      override def compute(s: Partition, context: TaskContext): Iterator[T] = {
        new InterruptibleIterator(context, s.asInstanceOf[ParallelCollectionPartition[T]].iterator)
      }
    
      override def getPreferredLocations(s: Partition): Seq[String] = {
        locationPrefs.getOrElse(s.index, Nil)
      }
    
    • 把握好5个主要属性很容易实现自定义的RDD
  • 相关阅读:
    海尔大数据精准营销平台(内部资料)
    马化腾做的PPT:产品设计与用户体验
    网站上线后,第一次完成线上线下整个环节
    灵感不断
    redis命令
    Redis持久化实践及灾难恢复模拟
    [转]创业公司常见的25个法律问题
    用python语言编写网络爬虫
    Python3常用网络编程模块介绍
    Python3数据库模块(sqlite3,SQLite3)
  • 原文地址:https://www.cnblogs.com/andyhe/p/10827393.html
Copyright © 2020-2023  润新知