什么是 RDD?【学习笔记】

一、什么是 RDD(从源码解读)

1、A Resilient Distributed Dataset (RDD), the basic abstraction in Spark.

RDD 弹性分布式数据集,是 Spark 中的最基本抽象。

Resilient ==>  指的是RDD的分区(代表着RDD数据分为几份)数量是可以进行弹性控制的

Distributed ==>  指的是RDD的分区分布式的存在于各个执行(Executor)节点上/task运行是分布式的;

Dataset ==>  RDD中描述的是一个数据集,类似于scala语法中 ArrayBuffer ListBuffer 大的数据集合,不过是分布式的。

2、Represents an immutable, partitioned collection of elements that can be operated on in parallel.

代表着一个不可变的,可以分区的(切片)的,元素可以被并行化的操作分布式的集合。

✓  不可变指的是从语法角度讲相当于定长 Array 和不可变的 List,所有的并行化操作(修改和更新)都将产生新的 Array 和 List,也就 和 MR 一样倾向于创建新数据,而不是对原数据进行修改。

 

二、RDD 的五大特性

*Internally,each RDD is characterized by five main properties:

 从内部来讲每个RDD都基本以下五个属性(特性): 

*-A list of partitions

1) 每个RDD都有一系列的分区组成,相当于HDFSblock,或者是MapReduce读取的切片

*-A function for computing each split

2) 每个分片或分区上都使用一个共同的函数来进行计算/执行/迭代,e.g.  val pairs = words.map(word=>(word,1))

*-A list of dependencies on other RDDs

3) 一系列的依赖:除了刚创建的的RDD(textFile读取进来)之外,其他的RDD都有依赖,即 words =pairs,那么pairs就依赖于words

*-Optionally,a Partitioner for key-value RDDs(e.g.to say that the RDD is hash-partitioned)

4) 可选的,对于key-value的这种pair类型的RDD,用户可以根据需要自己指定分区方式,比如 hash range

*-Optionally,a list of preferred locations to compute each split on(e.g.blocklocationsfor an HDFS file)

5) 可选的,每个切片在执行的时候, spark 都会为其寻找最优执行位置,已达到最理想的运行速度,类似于 mr 读取切片时候的就近原则

 

三、RDD 的创建方式

方式一:并行化在Driver端的已存在的数据集

举例,如下:

val data = Seq(1,2,3,4,5)

val rdd = sc.parallelize(data1)

​----------------------------------------------------------------------------------

scala> val a = Array(1,2,3,4,5)

a: Array[Int] = Array(1, 2, 3, 4, 5)

scala> val rdd0 = sc.parallelize(a)

rdd0: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[10] at parallelize at <console>:26

----------------------------------------------------------------------------------

scala> val b = List(1,2,3,4,5)

b: List[Int] = List(1, 2, 3, 4, 5)

scala> val rdd1 = sc.parallelize(b)

rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[11] at parallelize at <console>:26

-----------------------------------------------------------------------------------

scala> val c = Seq(1,2,3,4,5)

c: Seq[Int] = List(1, 2, 3, 4, 5)

scala> val rdd2 = sc.parallelize(c)

rdd2: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[12] at parallelize at <console>:26

-----------------------------------------------------------------------------------

scala> val d = scala.collection.mutable.ArrayBuffer(1,2,3,4,5)

d: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5)

scala> val rdd3 = sc.parallelize(d)

rdd3: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[13] at parallelize at <console>:26

-----------------------------------------------------------------------------------

scala> val rdd4 = sc.parallelize(1 to 10)

rdd4: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[14] at parallelize at <console>:24

-----------------------------------------------------------------------------------

默认情况下无论数据集大小,生成的分区数由  math.min(defaultParallelism,2)  决定,defaultParallelism=运行当前程序的分配的CPU的核

 

注意:

如果数据集比较大,SparkContext.parallelize(seq: Seq[T], numSlices: Int = defaultParallelism=2),注意调整 numSlices 增加并行度

 

方式二:引用外部数据源(分布式文件系统:HDFS,HBase,任何提供了 Hadoop InputFromt 接口)

InputFormat

-1. FileInputFormat(text)

-2. DBInputForamt(关系型数据库)

-3. TableInputFormat(HBase)

 

val rdd = sc.textFile("/input/wc.txt")

textFile(path: String, minPartitions: Int = defaultMinPartitions ) ,默认的最小分区数是 2

hadoopFile(path,

classOf[TextInputFormat],

classOf[LongWritable],

classOf[Text],minPartitions)

    .map(pair => pair._2.toString).setName(path)=>/input/wc.txt[(每一行的偏移量,每一行的内容)].map()

 

rdd.repartition(4)

拓展阅读:

[转自 “ _和 ] spark将数据写入HBase以及从HBase读取数据

https://blog.csdn.net/u011812294/article/details/72553150

 

方式三:调用自身Transformation算子处理已存在的RDD,生成新的子RDD

比如:

map()

flatMap()

filter()

mapPartitions()

mapPartitionsWithIndex()

sample()

union()

intersection()

distinct()

groupByKey()

reduceByKey()

sortByKey()

join()

cogroup

cartesion()

pipe()

coalesce()

repartition()

partitionBy()

......

 

四、RDD Operations 算子(或操作)的类型

官方定义:RDDs support two types of operations:transformations, which create a new dataset from an existing one,and actions, which return a value to the driver program after running a computation on the dataset

1、transformations(转换)

从已有的rdd来创建,返回值是一个新的RDD,数据依然在Executor

特点:所有的transformations算子都是懒加载,不会立即触发计算,不会形成job。

2、actions(行为/动)

对RDD使用compute的function,对算据集进行计算,并将结果返回给Driver端,或者保存到外部存储系统,返回值不是新RDD,这类操作会形成job。

比如:count、reduce、collect、take……

 在实际开发中,慎重使用最好不使用collect,因为会拉取所有数据,瞬间拉爆spark,使用 take() 代替。

 

从网上有看到,有些人将 persist/cache 算子(持久化)算作一种类型。但实际上,缓存 persist/cache 是懒加载的,应该算作 transformations 类型算子,而 unpersist/uncache 是紧急的,算作 actions 类型算子。

 

说到这里,简单比较一下 persist/cache 的区别:

a. 相同之处,都可以将 RDD 的数据在 Executor 内存中进行缓存,当一个 RDD 的数据会被多个后续的 job 使用的时候,可以进行进行缓存,好处在于在后续 job 执行的时候不需要从头进行计算,当后续的某个数据丢失的时候也不需要从头计算。;

b. 不同之处cache的缓存级别只有 MEMORY_ONLY(只有内存),而 persist 有 12 个级别的缓存(可以查看spark源码),其实cache 就是 persist(MEMORY_ONLY);

c. cache 不需要用户手动释放,而后者需要调用 unpersist;

d. persist/cache 是懒加载,而释放缓存是紧急的,可以通过 4040 监控页面 Storage 查看到。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值