Spark RDD 常用算子解析
一、转换算子 Transformation(lazy)
对于转换操作,RDD的所有转换都不会直接计算结果。 Spark仅记录作用于RDD上的转换操作逻辑,当遇到动作算子( Action)时才会进行真正计算。
RDD常见转换算子如下表:
Transformation | 描述 |
---|---|
map(func) | 通过函数func作用于 源 RDD中 的每个元素,返回一个新的 RDD |
filter(func) | 选择源RDD中的使得函数 func为 true的元素,返回一个新的 RDD |
flatMap(func) | 与map类似,但是每个输入项可以映射到 0或多个输出项 (因此 func应该返回一个 Seq,而不是单个项 ) |
mapPartitions(func) | 与map类似,但是在 RDD的每个分区上单独运行,所以 func在类型为 T的 RDD上运行时 必须是类型 Iterator<T> => Iterator<U> |
mapPartitionsWithIndex(func) | 与mapPartitions类似,但为 func多提供一个分区编号 ,所以 func类型为:(Int, Iterator<T>) => Iterator<U> |
sample(withReplacement, fraction, seed) | 使用给定的随机数生成器种子对数据的一部分进行采样 |
union(otherDataset) | 返回一个新数据集,该数据集包含源数据集中的元素和参数的并集 |
intersection(otherDataset) | 返回一个新的RDD,其中包含源数据集中的元素和参数的交集 |
distinct([numPartitions])) | 返回包含源数据集的不同元素的新数据集 |
groupByKey([numPartitions]) | 当调用一个(K, V)对的数据集时,返回一个 (K,Iterable<V>)对的数据集 |
aggregateByKey(zeroValue)(seqOp,combOp,[numPartitions]) | seqOp操作会聚合各分区中的元素,然后combOp操作把所有分区的聚合结果再次聚合,两个操作的初始值都是 zeroValue. seqOp的操作是遍历分区中的所有元素 (T),第一个 T跟 zeroValue做操作,结果再作为与第二个 T做操作的 zeroValue,直到遍历完整个分区。 combOp操作是把各分区聚合的结果,再聚合 |
sortByKey([ascending],[numPartitions]) | 根据key进行排序,默认为升序 ascending: Boolean = true |
join(otherDataset,[numPartitions]) | 当在类型(K, V)和 (K, W)的数据集上调用时,返回一个 (K (V, W))对的数据集,其中包含每个键的所有对元素。外部连接由 leftOuterJoin、 rightOuterJoin和 fullOuterJoin支持 |
cogroup(otherDataset,[numPartitions]) | 当调用类型(K, V)和 (K, W)的数据集时,返回一个 (K(Iterable Iterable))元组的数据集。这个操作也称为groupWith |
cartesian(otherDataset) | 在类型为T和 U的数据集上调用时,返回一个 (T, U)对 (所有对元素 )的数据集 |
pipe(command, [envVars]) | 通过shell命令 (例如 Perl或 bash脚本 )对 RDD的每个分区进行管道传输。将 RDD元素写入进程的stdin,并将其输出到 stdout的行作为字符串 RDD返回 |
coalesce(numPartitions) | 将RDD中的分区数量减少到 numpartition |
repartition(numPartitions) | 随机地重新Shuffle RDD中的数据,以创建更多或更少的分区,并在它们之间进行平衡 |
二、动作算子 Actions(non-lazy)
Action | 描述 |
---|---|
reduce(func) | 使用函数func(它接受两个参数并返回一个 )聚合数据集的元素 |
collect() | 在驱动程序Driver 中以数组的形式返回数据集的所有元素 |
count() | 返回数据集中元素的数量 |
first() | 返回数据集的第一个元素(类似于 take(1)) |
take(n) | 返回一个包含数据集前n个元素的数组 |
takeSample(withReplacement, num, [seed]) | 返回一个数组,其中包含数据集的随机num元素样本,可以替换,也可以不替换,可以预先指定随机数生成器种子 |
takeOrdered(n, [ordering]) | 使用RDD的自然顺序或自定义比较器返回 RDD的前n个元素 |
saveAsTextFile(path) | 将数据集的元素作为文本文件(或文本文件集 )写入本地文件系统、 HDFS或任何其他 hadoop支持的文件系统的给定目录中。 Spark将对每个元素调用 toString,将其转换为文件中的一行文本 |
saveAsSequenceFile(path) | 将数据集的元素作为Hadoop SequenceFile写入本地文件系统、 HDFS或任何其他 Hadoop支持的文件系统的给定路径中。这在实现 Hadoop的可写接口的键值对的 RDDs上是可用的。在 Scala中,它也可用于隐式转换为可写的类型 (Spark包括对Int、 Double、 String等基本类型的转换 ) |
saveAsObjectFile(path) | 使用Java序列化以简单的格式编写数据集的元素,然后可以使用 SparkContext.objectFile()加载这些元素 |
countByKey() | 仅在类型(K, V)的 RDDs上可用。返回 (K, Int)对的Map表示 每个键的计数 |
foreach(func) | 对数据集的每个元素运行函数func |
三、实例解析
通过函数func作用于源RDD中的每个元素,返回一个新的RDD
示例:
object MapDemo extends App {
//创建一个spark context对象
val conf: SparkConf = new SparkConf().setMaster("local[6]").setAppName("sparkTest6")
val sc: SparkContext = SparkContext.getOrCreate(conf)
//创建一个RDD
val a: RDD[Int] = sc.parallelize(1 to 10)
a.collect().foreach(println)
//TODO: map 对前一个rdd里面传过来的数据,每一个元素做一个操作
private val b: RDD[Int] = a.map(x=>x*2) //简写a.map(_*2)
println("----------分割线-----------")
b.collect().foreach(println)
//TODO: 使用map将普通RDD转换成pairRDD
private val c: RDD[(Int, Int)] = a.map(x=>(x,1))
println("----------分割线-----------")
println(c.collect().mkString("--"))
sc.stop()
}
/*控制台打印结果
1
2
3
4
5
6
7
8
9
10
----------分割线-----------
2
4
6
8
10
12
14
16
18
20
(1,1)--(2,1)--(3,1)--(4,1)--(5,1)--(6,1)--(7,1)--(8,1)--(9,1)--(10,1)
*/
选择源RDD中的使得函数 func为 true的元素,返回一个新的 RDD
示例:
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
object FilterRDD extends App {
//创建一个spark context对象
val conf: SparkConf = new SparkConf().setMaster("local[6]").setAppName("sparkTest6")
val sc: SparkContext = SparkContext.getOrCreate(conf)
//创建一个RDD
val a: RDD[Int] = sc.parallelize(1 to 10)
//TODO:过滤满足a中元素能被2整除则转化为RDD b
private val b: RDD[Int] = a.filter(x=>x%2==0)
println(b.collect().mkString(" "))
sc.stop()
}
//控制台打印结果:2 4 6 8 10
与map类似,但是每个输入项可以映射到 0或多个输出项 (因此 func应该返回一个 Seq,而不是单个项 )
示例:
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
object Demo extends App {
//创建一个spark context对象
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("sparkTest")
val sc: SparkContext = SparkContext.getOrCreate(conf)
private val rdd1: RDD[String] = sc.parallelize(Array("hello java","hello scala","hello python"))
private val rdd2: RDD[String] = rdd1.flatMap(x=>x.split(" "))
rdd2.collect().foreach(println)
}
/*
hello
java
hello
scala
hello
python
*/
mapPartitions(func)
与map类似,但是在 RDD的每个分区上单独运行,所以 func在类型为 T的 RDD上运行时 必须是类型 Iterato<T> => Iterator<U>
示例:
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD
object MapPartitionsDemo extends App {
//创建一个spark context对象
val conf: SparkConf = new SparkConf().setMaster("local[6]").setAppName("sparkTest6")
val sc: SparkContext = SparkContext.getOrCreate(conf)
val a: RDD[Int] = sc.parallelize(1 to 10)
//TODO: map 对前一个rdd里面传过来的数据,每一个元素做一个操作
val b: RDD[Int] = a.map(x=>x*2)
b.collect().foreach(println)
println("---------分割线------------")
//TODO:mapPartitions每次处理一个分区的数据
private val rdd2: RDD[Int] = a.mapPartitions(x=>x.map(_*2))
println(rdd2.collect().mkString(" "))
sc.stop()
}
/*
2
4
6
8
10
12
14
16
18
20
---------分割线------------
2 4 6 8 10 12 14 16 18 20
*/
与mapPartitions类似,但为 func多提供一个分区编号 ,所以 func类型为:(Int, Iterator<T>) => Iterator<U>
示例:
sample(withReplacement, fraction, seed)
使用给定的随机数生成器种子对数据的一部分进行采样
示例:
返回一个新数据集,该数据集包含源数据集中的元素和参数的并集
示例:
返回一个新的RDD,其中包含源数据集中的元素和参数的交集
示例:
返回包含源数据集的不同元素的新数据集
示例:
当调用一个(K, V)对的数据集时,返回一个 (K,Iterable)对的数据集
示例:
aggregateByKey(zeroValue)(seqOp,combOp,[numPartitions])
seqOp操作会聚合各分区中的元素,然后combOp操作把所有分区的聚合结果再次聚合,两个操作的初始值都是 zeroValue. seqOp的操作是遍历分区中的所有元素 (T),第一个 T跟 zeroValue做操作,结果再作为与第二个 T做操作的 zeroValue,直到遍历完整个分区。 combOp操作是把各分区聚合的结果,再聚合
示例:
sortByKey([ascending],[numPartitions])
根据key进行排序,默认为升序 ascending: Boolean = true
示例:
join(otherDataset,[numPartitions])
当在类型(K, V)和 (K, W)的数据集上调用时,返回一个 (K (V, W))对的数据集,其中包含每个键的所有对元素。外部连接由 leftOuterJoin、 rightOuterJoin和 fullOuterJoin支持
示例:
cogroup(otherDataset,[numPartitions])
当调用类型(K, V)和 (K, W)的数据集时,返回一个 (K(Iterable Iterable))元组的数据集。这个操作也称为groupWith
示例:
在类型为T和 U的数据集上调用时,返回一个 (T, U)对 (所有对元素 )的数据集
示例:
通过shell命令 (例如 Perl或 bash脚本 )对 RDD的每个分区进行管道传输。将 RDD元素写入进程的stdin,并将其输出到 stdout的行作为字符串 RDD返回
示例:
将RDD中的分区数量减少到 numpartition
示例:
随机地重新Shuffle RDD中的数据,以创建更多或更少的分区,并在它们之间进行平衡
示例:
使用函数func(它接受两个参数并返回一个 )聚合数据集的元素
示例:
在驱动程序Driver 中以数组的形式返回数据集的所有元素
示例:
返回数据集中元素的数量
示例:
返回数据集的第一个元素(类似于 take(1))
示例:
返回一个包含数据集前n个元素的数组
示例:
takeSample(withReplacement, num, [seed])
返回一个数组,其中包含数据集的随机num元素样本,可以替换,也可以不替换,可以预先指定随机数生成器种子
示例:
使用RDD的自然顺序或自定义比较器返回 RDD的前n个元素
示例:
将数据集的元素作为文本文件(或文本文件集 )写入本地文件系统、 HDFS或任何其他 hadoop支持的文件系统的给定目录中。 Spark将对每个元素调用 toString,将其转换为文件中的一行文本
示例:
将数据集的元素作为Hadoop SequenceFile写入本地文件系统、 HDFS或任何其他 Hadoop支持的文件系统的给定路径中。这在实现 Hadoop的可
示例:
使用Java序列化以简单的格式编写数据集的元素,然后可以使用 SparkContext.objectFile()加载这些元素
示例:
仅在类型(K, V)的 RDDs上可用。返回 (K, Int)对的Map表示 每个键的计数
示例:
对数据集的每个元素运行函数func
示例: