1. Spark的RDD

RDD(Resilient Distributed Datasets),弹性分布式数据集,是对分布式数据集的一种抽象。
RDD所具备5个主要特性:
  • 一组分区列表
  • 计算每一个数据分片的函数
  • RDD上的一组依赖
  • 对于Key Value 对的RDD,会有一个Partitioner, 这是数据的分区器,控制数据分区策略和数量
  • 一组Preferred Location信息(如HDFS 上的数据块地址)
上图是一个简单的CoGroupedRDD满足了RDD 5个特性
 

2. RDD的两种操作

2.1 Transformation

Transformation: 转换,从现有的数据集创建一个新的数据集,从一个RDD转换成另一个RDD,transformation的操作是延迟计算的,在Driver层就构建好RDD之间的关系,数据分区策略,但并不提交计算。
Transformations 按照数据类型纬度分为:Value数据类型和Key-Value的数据类型的Transformation

2.1.1 Value型Transformation

针对以Value为输入值的RDD,常见的Map, FlatMap....,而输出值并不一定是value,也有可能是Key,Value的数据类型
以输入分区和输出分区的数据关系类型
  1. 输入分区和输出分区1对1 例如 map
  2. 输入分区和输出分区多对1 例如 union
  3. 输入分区和输出分区多对多 例如 groupBy
  4. 输入分区包含输出分区 例如 filter

2.1.2 Key-Value型Transformation

针对Key,Value的输入类型,进行聚集,连接等操作
Spark 里处理Key,Value的输入类型有个专门的类来处理
class PairRDDFunctions[K, V](self: RDD[(K, V)])
(implicit kt: ClassTag[K], vt: ClassTag[V], ord: Ordering[K] = null)
extends Logging with Serializable {
}

2.1.2.1 RDD 转 PairRDDFunctions

会不会很奇怪,并没有继承RDD,也就是说严格意义上来说,K-V的算子并不是RDD,先看看一个例子:

line.flatMap(_.split(" "))
.map((_, ))
.reduceByKey(_+_).collect().foreach(println)

reduceByKey是一个Key-Value的算子

def map[U: ClassTag](f: T => U): RDD[U] = withScope {
val cleanF = sc.clean(f)
new MapPartitionsRDD[U, T](this, (context, pid, iter) => iter.map(cleanF))
}
在rdd.scala中map函数中,返回的类型是MapPartitionsRDD,并不是PairRDDFunctions,如何转换的?
在scala语言里有个语法叫做“scala implicit method”,在隐式转化里我们看到了定义
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)
}
将rdd自动转为PairRDDFunctions,最后调用了算子reduceByKey

2.1.2.1 PairRDDFunctions 转 RDD

Spark的核心抽象RDD是各个组件交互的核心,也是API里的主要接口,显然不能使用对象PairRDDFunctions作为RDD之间的交互。
PairRDDFunctions的初始化的时候会带入一个RDD,这是父类的RDD
@Experimental
def combineByKeyWithClassTag[C](
createCombiner: V => C,
mergeValue: (C, V) => C,
mergeCombiners: (C, C) => C,
partitioner: Partitioner,
mapSideCombine: Boolean = true,
serializer: Serializer = null)(implicit ct: ClassTag[C]): RDD[(K, C)] = self.withScope {
require(mergeCombiners != null, "mergeCombiners must be defined") // required as of Spark 0.9.0
if (keyClass.isArray) {
if (mapSideCombine) {
throw new SparkException("Cannot use map-side combining with array keys.")
}
if (partitioner.isInstanceOf[HashPartitioner]) {
throw new SparkException("HashPartitioner cannot partition array keys.")
}
}
val aggregator = new Aggregator[K, V, C](
self.context.clean(createCombiner),
self.context.clean(mergeValue),
self.context.clean(mergeCombiners))
if (self.partitioner == Some(partitioner)) {
self.mapPartitions(iter => {
val context = TaskContext.get()
new InterruptibleIterator(context, aggregator.combineValuesByKey(iter, context))
}, preservesPartitioning = true)
} else {
new ShuffledRDD[K, V, C](self, partitioner)
.setSerializer(serializer)
.setAggregator(aggregator)
.setMapSideCombine(mapSideCombine)
}
}
当调用K-V算子的时候,可以单独指定分区器,否则算子会自己构建一个HashPartitioner的分区器而分区策略依赖输入的分片块, 通过判断数据的分区器是否和父RDD的一致,构建ShuffledRDD,MapPartitionsRDD

2.2 Action

 在前面谈到Transformation都是延迟计算的,原因也很简单,所有的计算都需要最后的结果展现,如果我不想获取结果,用于计算、保存,那么计算就没有意义了,也就不需要计算了,所以用于最后需要计算的前提是需要有Action,结果展现。
比较常见的:
  • 无输出 foreach
  • 输出到文件或者HDFS
  • Scala的集合等数据类型 collect, count
在Action中,比如collect
def collect(): Array[T] = withScope {
val results = sc.runJob(this, (iter: Iterator[T]) => iter.toArray)
Array.concat(results: _*)
}

调用SparkContext运行Job

def runJob[T, U: ClassTag](
rdd: RDD[T],
func: (TaskContext, Iterator[T]) => U,
partitions: Seq[Int],
resultHandler: (Int, U) => Unit): Unit = {
if (stopped.get()) {
throw new IllegalStateException("SparkContext has been shutdown")
}
val callSite = getCallSite
val cleanedFunc = clean(func)
logInfo("Starting job: " + callSite.shortForm)
if (conf.getBoolean("spark.logLineage", false)) {
logInfo("RDD's recursive dependencies:\n" + rdd.toDebugString)
}
dagScheduler.runJob(rdd, cleanedFunc, partitions, callSite, resultHandler, localProperties.get)
progressBar.foreach(_.finishAll())
rdd.doCheckpoint()
}
SparkContext运行Job,最终就是调用了DAG 进行job的调度,关于 DAG的具体会在后面一篇讲到

3. RDD的依赖关系

protected def getDependencies: Seq[Dependency[_]] = deps  

RDD可以通过getDependencies获取到依赖的数组

@DeveloperApi
abstract class Dependency[T] extends Serializable {
def rdd: RDD[T]
}
对Dependency来说会保存Parent 的RDD, 可以通过RDD的Dependency来获取双亲的RDD,这样就能溯源
 
依赖上整体分为Narrow 和Shuffle 两类,也有人叫窄依赖,宽依赖
 
NarrowDependency 分为三类
  1. 1对1  OneToOneDependency:  常见MapRDD
  2. 多对1 RangDependency: UnionRDD
  3. 1 对部分 PruneDependency: 裁剪
ShuffleDependency 多对多,对应的是ShuffleRDD
 
只有Transformation的RDD之间才会有Dependency,而对Action来说是并不存在Dependency
 
整个RDD的分析,构建依赖,数据分片,最后通过Action提交到DAG调度,都是在Driver的主线程完成,这时候并没有构建好Job。

Spark Core (一) 什么是RDD的Transformation和Action以及Dependency(转载)的更多相关文章

  1. 03、操作RDD(transformation和action案例实战)

    1.transformation和action介绍 Spark支持两种RDD操作:transformation和action.transformation操作会针对已有的RDD创建一个新的RDD:而a ...

  2. Spark Core(三)Executor上是如何launch task(转载)

    1. 启动任务 在前面一篇博客中(Driver 启动.分配.调度Task)介绍了Driver是如何调动.启动任务的,Driver向Executor发送了LaunchTask的消息,Executor接收 ...

  3. Spark RDD/Core 编程 API入门系列 之rdd实战(rdd基本操作实战及transformation和action流程图)(源码)(三)

    本博文的主要内容是: 1.rdd基本操作实战 2.transformation和action流程图 3.典型的transformation和action RDD有3种操作: 1.  Trandform ...

  4. spark core (二)

    一.Spark-Shell交互式工具 1.Spark-Shell交互式工具 Spark-Shell提供了一种学习API的简单方式, 以及一个能够交互式分析数据的强大工具. 在Scala语言环境下或Py ...

  5. spark RDD transformation与action函数整理

    1.创建RDD val lines = sc.parallelize(List("pandas","i like pandas")) 2.加载本地文件到RDD ...

  6. Spark学习笔记之RDD中的Transformation和Action函数

    总算可以开始写第一篇技术博客了,就从学习Spark开始吧.之前阅读了很多关于Spark的文章,对Spark的工作机制及编程模型有了一定了解,下面把Spark中对RDD的常用操作函数做一下总结,以pys ...

  7. Spark Core源代码分析: RDD基础

    RDD RDD初始參数:上下文和一组依赖 abstract class RDD[T: ClassTag]( @transient private var sc: SparkContext, @tran ...

  8. Spark Core(四)用LogQuery的例子来说明Executor是如何运算RDD的算子(转载)

    1. 究竟是怎么运行的? 很多的博客里大量的讲了什么是RDD, Dependency, Shuffle.......但是究竟那些Executor是怎么运行你提交的代码段的? 下面是一个日志分析的例子, ...

  9. Spark RDD概念学习系列之Pair RDD的transformation操作

    不多说,直接上干货! Pair RDD的transformation操作 Pair RDD转换操作1 Pair RDD 可以使用所有标准RDD 上转化操作,还提供了特有的转换操作. Pair RDD转 ...

随机推荐

  1. CSS 解决IE6双倍距离BUG

    只要满足下面3个条件才会出现这个BUG: 1)要为块状元素:        2)要左侧浮动:        3)要有左外边距(margin-left): 解决这个BUG很容易,只需要在相应的块状元素的 ...

  2. 浏览器地址栏中加入ico图标的二种方法

    在你的网页文件之间加入下面代码: 1.在URL地址栏中显示ico 2.在收藏夹中显示ico link href="/favicon.ico" type="image/x- ...

  3. java总结(1)——java的特点

    之前学习java仅仅是单纯的学习,老师要求学习.所以就学习.可是没有细致考虑过java的一些特别之处,比方,我们为什么要学习java而不是其它的语言,它必定有选择它的特点.所以,从如今開始,仅仅有埋头 ...

  4. HDU 2594 Simpsons’ Hidden Talents (KMP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2594 这题直接用KMP算法就能够做出来,只是我还尝试了用扩展的kmp,这题用扩展的KMP效率没那么高. ...

  5. day22<IO流+>

    IO流(序列流) IO流(序列流整合多个) IO流(内存输出流) IO流(内存输出流之黑马面试题) IO流(对象操作流ObjecOutputStream) IO流(对象操作流ObjectInputSt ...

  6. ionic creator(ionic生成器)

    用来生成前端 html 还是挺方便的(接口数据另算),弄好就可以直接下载 https://creator.ionic.io/app/dashboard/projects

  7. 经典 MapReduce框架(MRv1)

    在 MapReduce 框架中,作业执行受两种类型的进程控制: 一个称为 JobTracker 的主要进程,它协调在集群上运行的所有作业,分配要在 TaskTracker 上运行的 map 和 red ...

  8. Linux wc 命令

    wc命令可以用来统计文件的行数 .单词数 .字符数,用法如下: [root@localhost ~]$ wc 1.txt # 统计文件的行数.单词数.字符数 2 4 24 1.txt [root@lo ...

  9. canvas二:绘制圆和其他曲线

    1.绘制圆 绘制圆是canvas里面不可缺少的功课,而且绘制圆在canvas中的用处很多,好嘞,开扯 绘制圆需要用到arc这个方法: arc(X坐标,Y坐标,半径,起始弧度,结束弧度,旋转方向): 弧 ...

  10. LLDB调试器

    你是否曾经苦恼于理解你的代码,而去尝试打印一个变量的值? NSLog(@"%@", whatIsInsideThisThing); 或者跳过一个函数调用来简化程序的行为? NSNu ...