Spark—常用的RDD行动算子
在RDD的创建一文中 >> Spark—RDD的创建(Local环境),讲到RDD在Yarn模式的工作原理时提到了算子的简单介绍,在这里会稍作原理性的补充。
文章目录
一、算子?
算子 : Operator(操作)
- RDD的方法和Scala集合对象的方法不一样
- 集合对象的方法都是在同一个节点的内存中完成的。
- RDD的方法可以将计算逻辑发送到Executor端(分布式节点)执行为了区分不同的处理效果,所以将RDD的方法称之为算子。
- RDD的方法外部的操作都是在Driver端执行的,而方法内部的逻辑代码是在Executor端执行。
二、行动算子
常用转换算子可以戳这里 >> Spark—常用的RDD转换算子
1. reduce
- 函数签名
def reduce(f: (T, T) => T): T
- 函数说明
聚集 RDD 中的所有元素,先聚合分区内数据,再聚合分区间数据
代码如下(示例):
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
val sc = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List(1,2,3,4))
// reduce
// result: 10
val reduceRes: Int = rdd.reduce(_+_)
println(reduceRes)
2. collect
-
函数签名
def collect(): Array[T] = withScope { val results = sc.runJob(this, (iter: Iterator[T]) => iter.toArray) Array.concat(results: _*) }
-
函数说明
在驱动程序中,以数组 Array 的形式返回数据集的所有元素
代码如下(示例):
// collect : 方法会将不同分区的数据按照分区顺序采集到Driver端内存中,形成数组
// result: 1,2,3,4
val rdd = sc.makeRDD(List(1,2,3,4))
val collect: Array[Int] = rdd.collect()
println(collect.mkString(","))
3. count
-
函数签名
/** * Return the number of elements in the RDD. */ def count(): Long = sc.runJob(this, Utils.getIteratorSize _).sum
-
函数说明
返回 RDD 中元素的个数
// count : 数据源中数据的个数
// result: 4
val rdd = sc.makeRDD(List(1,2,3,4))
val cnt = rdd.count()
println(cnt)
4. first
-
函数签名
/** * Return the first element in this RDD. */ def first(): T = withScope { take(1) match { case Array(t) => t case _ => throw new UnsupportedOperationException("empty collection") } }
-
函数说明
返回 RDD 中的第一个元素
// first : 获取数据源中数据的第一个
// result: 1
val rdd = sc.makeRDD(List(1,2,3,4))
val first = rdd.first()
println(first)
5. take
-
函数签名
def take(num: Int): Array[T]
-
函数说明
返回一个由 RDD 的前 n 个元素组成的数组
// take : 获取N个数据
// result: 1,2,3
val rdd = sc.makeRDD(List(1,2,3,4))
val takeRes: Array[Int] = rdd.take(3)
println(takeRes.mkString(","))
6. takeOrdered
-
函数签名
def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]
-
函数说明
返回该 RDD 排序后的前 n 个元素组成的数组
// takeOrdered : 数据排序后,取N个数据
// result: 1,2,3
val rdd1 = sc.makeRDD(List(4,2,3,1))
val takeOrdered: Array[Int] = rdd1.takeOrdered(3)
println(takeOrdered.mkString(","))
7. aggregate
-
函数签名
def aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
-
函数说明
分区的数据通过初始值和分区内的数据进行聚合,然后再和初始值进行分区间的数据聚合
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
val sc = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List(1,2,3,4),2)
// aggregate : 初始值会参与分区内计算,并且和参与分区间计算
//10 + [10 + (1+2)] + [10 + (3+4)]= 40
val result = rdd.aggregate(10)(_+_, _+_)
println(result)
sc.stop()
8. fold
-
函数签名
def fold(zeroValue: T)(op: (T, T) => T): T
-
函数说明
折叠操作,aggregate 的简化版操作
// 分区内与分区间的运算相同,可以简化
val result1 = rdd.fold(10)(_+_)
println(result1)
9. countByKey & countByValue
-
函数签名
def countByKey(): Map[K, Long] = self.withScope { self.mapValues(_ => 1L).reduceByKey(_ + _).collect().toMap } def countByValue()(implicit ord: Ordering[T] = null): Map[T, Long] = withScope { map(value => (value, null)).countByKey() }
-
函数说明
countByKey : 统计每种 key 的个数, 元素必须是k-v类型
countByValue: 统计元素的个数
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
val sc = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List(1,1,1,4),2)
val rdd1 = sc.makeRDD(List(
("a", 1),("a", 2),("a", 3),("b", 3)
))
// TODO - 行动算子
val intToLong: collection.Map[Int, Long] = rdd.countByValue()
println(intToLong)
val stringToLong: collection.Map[String, Long] = rdd1.countByKey()
println(stringToLong)
/*
result:
Map(4 -> 1, 1 -> 3)
Map(b -> 1, a -> 3)
*/
sc.stop()
10. save 相关算子
-
函数签名
def saveAsTextFile(path: String): Unit def saveAsObjectFile(path: String): Unit def saveAsSequenceFile( path: String, codec: Option[Class[_ <: CompressionCodec]] = None): Unit
-
函数说明
将数据保存到不同格式的文件中
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
val sc = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List(1,1,1,4),2)
val rdd1 = sc.makeRDD(List(
("a", 1),("a", 2),("a", 3)
))
// TODO - 行动算子
// 普通文件
rdd.saveAsTextFile("output")
// 对象文件
rdd1.saveAsObjectFile("output1")
// saveAsSequenceFile方法要求数据的格式必须为K-V类型
// 序列文件
rdd1.saveAsSequenceFile("output2")
sc.stop()
11. foreach
-
函数签名
def foreach(f: T => Unit): Unit = withScope { val cleanF = sc.clean(f) sc.runJob(this, (iter: Iterator[T]) => iter.foreach(cleanF)) }
-
函数说明
分布式遍历 RDD 中的每一个元素,调用指定函数
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("Operator")
val sc = new SparkContext(sparkConf)
val rdd = sc.makeRDD(List(1,2,3,4))
// foreach 其实是Driver端内存集合的循环遍历方法
// 先用collect采集后打印,返回的是一个Array,属于scala的集合对象,集合对象的方法都是在同一个节点的内存中完成的。
rdd.collect().foreach(data => print(data+"\t"))
println()
println("******************")
// RDD的方法可以将计算逻辑发送到Executor端(分布式节点)执行
// foreach 其实是Executor端内存数据打印,
// RDD的方法外部的操作都是在Driver端执行的,而方法内部的逻辑代码是在Executor端执行。
// 分布式打印
rdd.foreach(data => print(data+"\t"))
/*
result:
1 2 3 4
******************
3 4 1 2
*/
sc.stop()
总结
文章也是仅作知识点的记录,欢迎大家指出错误,一起探讨~~~