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. 怎么输入MathType不等号

    MathType是一款比较常用的数学公式编辑器,我们在使用这款软件的时候常常需要输入各种符号.有些新用户对这款软件不是很熟悉,对于一些符号不知道怎么输入,下面我们来给大家介绍介绍MathType不等号 ...

  2. windows,cmd中,如何切换到磁盘的根目录下

    需求描述: 在windows的cmd中操作,有的时候也会遇到切换了很多的目录,然后需要切换到根目录的情况 操作过程: 1.通过cd \的方式,切换回当前磁盘的根目录下 备注:未切换之前,在Driver ...

  3. brew 接口的原理

    请查看相关文档的第9章 该文档可以csdn silentjesse帐号下的资源去下载 http://download.csdn.net/detail/silentjesse/5859077

  4. HTML表单的应用

    <html> <head> <title>HTML表单的应用</title> </head> <body> <!-- bo ...

  5. laravel 发送邮件

    1)邮件配置(config/mail.php 配置文件) MAIL_DRIVER                       邮箱驱动,laravel 支持 "smtp", &qu ...

  6. poj_2182 线段树/树状数组

    题目大意 n个数排成一排(不知道大小,只是占了一个位置),从a[1]到a[n]进行遍历,对于每个a[i],给出从a[1]到a[i-1]中小于a[i]数的个数.要求出 a[1]到a[n]中这n个数的相对 ...

  7. mongodb学习(二)

    昨天给ubuntu13.04安装ati的显卡驱动,ubuntu本来对ati的显卡支持不是很好,没办法unity启动器没有了,ccsm也没有任何作用,只得重新安装了12.10,近期也不打算升级13.04 ...

  8. 【linux系列】linux防火墙的关闭开启

    即时生效 开启:service iptables start 关闭:service iptables stop 重启后生效 开启:chkconfig iptables on 关闭:chkconfig ...

  9. 【linux系列】vmware12pro安装centos7

    安装参考:http://blog.csdn.net/guin_guo/article/details/49403889 安装完成之后ip还是不成功无法连接网络: 进入/etc/sysconfig/ne ...

  10. 关于Activity的getReferrer():如何在Activity中获取调用者?

    http://blog.csdn.net/u013553529/article/details/53856800 关于Activity的getReferrer()之一:如何在Activity中获取调用 ...