一:RDD概述
RDD定义:
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集。是Spark中最基本的数据抽象。代码中是一个抽象类,代表一个不可变、可分区、其中的元素可并行计算的集合。
RDD的属性
特点
RDD表示只读的分区的数据集,对RDD进行改动,只能通过RDD的转换操作,由一个RDD转换为一个新的RDD。新的RDD包含了其他RDD衍生所必须的额信息。RDDs之间存在历来,RDD的执行是按照血缘关系进行延迟计算的。如果血缘关系较长,可以通过持久化RDD来切断血缘关系。
二:RDD编程
编程模型
在 Spark 中, RDD 被表示为对象,通过对象上的方法调用来对 RDD 进行转换。经过一系列的 transformations 定义 RDD 之后,就可以调用 actions 触发 RDD 的计算, action 可以是向应用程序返回结果(count, collect 等),或者是向存储系统保存数据(saveAsTextFile 等)。在Spark 中,只有遇到 action,才会执行 RDD 的计算(即延迟计算),这样在运行时可以通过管道的方式传输多个转换。
RDD的创建:(集合中创建、外部存储中创建、其他RDD转换)
集合中创建:(parallelize和makeRDD)
val rdd = sc.parallelize(Array(1,2,3,4,5))
val rdd = sc.makeRDD(Array(1,2,3,4,5))
外部存储系统的数据集进行创建RDD
包括本地的文件系统,还有所有 Hadoop 支持的数据集,比如 HDFS、 Cassandra、 HBase 等,
val rdd2= sc.textFile("hdfs://hadoop102:9000/RELEASE"
RDD转换(下章单独解析)
三:RDD转换(面试开发重点)
Value类型
作用: 返回一个新的 RDD,该 RDD 由每一个输入元素经过 func 函数转换后组成
创建一个 1-10 数组的 RDD,将所有元素*2 形成新的 RDD
var source = sc.parallelize(1 to 10)
source.collect()
val mapadd = source.map(_*2)
mapadd.collect()
类似于 map,但独立地在 RDD 的每一个分片上运行,因此在类型为 T 的 RDD 上
运行时, func 的函数类型必须是 Iterator[T] => Iterator[U]。 假设有 N 个元素, 有 M 个分区,那么 map 的函数的将被调用 N 次,而 mapPartitions 被调用 M 次,一个函数一次处理分区内所有。
创建一个 RDD,使每个元素*2 组成新的 RDD
val rdd = sc.parallelize(Array(1,2,3,4))
rdd.mapPartitions(x=>map(_*2)).collect
类似于 mapPartitions,但 func 带有一个整数参数表示分片的索引值,因此在类型
为 T 的 RDD 上运行时, func 的函数类型必须是(Int, Interator[T]) => Iterator[U];
需求:创建一个 RDD,使每个元素跟所在分区形成一个元组组成一个新的 RDD
val rdd = sc.parallelize(Array(1,2,3,4))
val indexRdd = rdd,mapPartitionsWithIndex((index,items)=>(items.map((index,_))))
indexRdd.collect
作用:蕾仕于map,但是每一个输出元素可以被映射为0或者多个输出元素(所以func应该返回一个序列,而不是一个单一元素)
需求:创建一个元素为1-5的RDD,使用flatMap创建一个新的RDD,新的RDD为原来RDD的每个元素的2倍
val sourceFlat = sc.parallelize(1 to 5)
sourceFlat.collect()
val flatMapRdd = sourceFlat.flatMap(1 to _).collect()
结果:res12: Array[Int] = Array(1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5)
作用: 将每一个分区形成一个数组,形成新的 RDD 类型是 RDD[Array[T]]
需求:创建一个 4 个分区的 RDD,并将每个分区的数据放到一个数组
val rdd = sc.parallelize(1 to 16,4)
rdd.glom().collect()
结果:res25: Array[Array[Int]] = Array(Array(1, 2, 3, 4), Array(5, 6, 7, 8), Array(9, 10, 11, 12),Array(13, 14, 15, 16))
作用: 分组,按照传入函数的返回值进行分组。 将相同的 key 对应的值放入一个迭代器。
需求:创建一个 RDD,按照元素模以 2 的值进行分组。
val rdd = sc.parallzlize(1 to 4)
val group = rdd.groupBy(_%2).collect()
res0: Array[(Int, Iterable[Int])] = Array((0,CompactBuffer(2, 4)), (1,CompactBuffer(1, 3)))
作用: 过滤。 返回一个新的 RDD,该 RDD 由经过 func 函数计算后返回值为 true 的输入
元素组成。
需求:创建一个 RDD(由字符串组成),过滤出一个新 RDD(包含”xiao”子串)
var sourceFilter =sc.parallelize(Array("xiaoli",“xiaotian”,"zhangli"))
sourceFilter.filter(_.contains("xiao")).collect()
结果:res10: Array[String] = Array(xiaoli, xiaotian)
作用: 以指定的随机种子随机抽样出数量为 fraction 的数据, withReplacement 表示是抽
出的数据是否放回, true 为有放回的抽样, false 为无放回的抽样, seed 用于指定随机数生成
器种子。
需求:创建一个 RDD(1-10),从中选择放回和不放回抽样
val rdd = sc.parallelize(1 to 10)
//放回抽样
var sample1 = rdd.sample(true,0.4,2).collect()
//不放回抽样
var sample2 = rdd.sample(false,0.2,3)。collect()
作用: 对源 RDD 进行去重后返回一个新的 RDD。 默认情况下,只有 8 个并行任务来操
作,但是可以传入一个可选的 numTasks (并行度)参数改变它。
val distinctRdd = sc.parallelize(List(1,2,1,5,2,9,6,1))
val unionRDD = distinctRdd.distinct()。collect()
作用: 缩减分区数,用于大数据集过滤后,提高小数据集的执行效率。
需求:创建一个 4 个分区的 RDD,对其缩减分区
val rdd = sc.parallelize(1 to 16,4)
rdd.partitions.size
val coalesceRDD = rdd.coalesce(3)
rdd.partitions.size
repartition(numPartitions)案例(与上一个作用类似)
区别:
sortBy(func,[ascending],[numTasks])案例
1. 作用;使用 func 先对数据进行处理,按照处理后的数据比较结果排序,默认为正序。
2. 需求:创建一个 RDD,按照不同的规则进行排序
val rdd = sc.parallelize(List(2,1,3,4,5))
按照自身大小排序
rdd.sortBy(x=>x).collect()
按照与 3 余数的大小排序
rdd.sortBy(x=>x%3).collect()
1. 作用:管道,针对每个分区,都执行一个 shell 脚本,返回输出的 RDD。
注意:脚本需要放在 Worker 节点可以访问到的位置