Spark快速上手(6)Spark核心编程-RDD行动算子Action
RDD(3)
RDD行动算子
所谓行动算子,就是触发Job执行的方法
reduce
函数签名
def reduce(f: (T, T) => T): T
函数说明
聚集RDD中的所有元素,先聚合分区内数据,再聚合分区间数据
e.g.
code:
def main(args: Array[String]): Unit = {
val source: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))
// 聚合数据
val reduceResult: Int = source.reduce(_ + _)
println(reduceResult)
}
result:
10
collect
函数签名
def collect(): Array[T]
函数说明
在驱动程序中,以数组Array形式返回数据集中的所有元素
e.g.
code:
@Test
def testCollect(): Unit = {
// 收集数据到driver
source.collect().foreach(println)
}
count
函数签名
def count(): Long
函数说明
返回RDD中的元素的个数
e.g.
code:
@Test
def testCount(): Unit = {
// 返回 RDD 中元素的个数
println(source.count())
}
first
函数签名
def first(): T
函数说明
返回RDD中的第一个元素
e.g.
code:
@Test
def testFirst(): Unit ={
// 返回 RDD 中的第一个元素
println(source.first())
}
take
函数签名
def take(num: Int): Array[T]
函数说明
返回一个由 RDD 的前 n 个元素组成的数组
e.g.
code:
@Test
def testTake(): Unit = {
// 返回一个由RDD前n个元素组成的数组
println(source.take(2).mkString(","))
}
takeOrdered
函数签名
def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T]
函数说明
返回该RDD排序后的前n个元素组成的数组
e.g.
code:
@Test
def testTakeOrdered(): Unit = {
// 返回一个由RDD前n个元素排序后组成的数组
source.takeOrdered(2).foreach(println)
}
aggregate
函数签名
def aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
函数说明
分区的数据通过初始值和分区内的数据进行聚合,然后再和初始值进行分区间的数据聚合
e.g.
code:
@Test
def testAggregate(): Unit = {
// 将该 RDD 所有元素相加得到结果
//val result: Int = rdd.aggregate(0)(_ + _, _ + _)
println(source1.aggregate(10)(_ + _, _ + _))
}
note:
这里的结果 如果按照aggregateByKey算子运算会是30,但是使用aggregate算子运算是40,这是因为aggregateByKey中的初始
值智慧参与一次分区内的运算,而aggregate会参加分区内的运算后,还会参加分区间的运算
fold
函数签名
def fold(zeroValue: T)(op: (T, T) => T): T
函数说明
折叠操作,aggregate的简化版操作
@Test
def testFold(): Unit = {
// 折叠操作,aggregate的简化版操作
println(source1.fold(0)(_ + _))
}
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() }
函数说明
统计每种key/value的个数
val source1: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
val source2: RDD[(Int, String)] = sc.makeRDD(List((1, "a"), (2, "a"), (1, "a"), (3, "c")))
@Test
def testCountByKey_CountByValue(): Unit = {
// 统计每种 value 的个数
println(source1.countByValue())
// 统计每种 key 的个数
println(source2.countByKey())
}
save相关算子
函数签名
def saveAsTextFile(path: String): Unit
def saveAsObjectFile(path: String): Unit
def saveAsSequenceFile(path: String,codec: Option[Class[_ <: CompressionCodec]] = None): Unit
函数说明
将数据保存到不同格式的文件中
@Test
def testSave(): Unit ={
// 保存成 Text 文件
source2.saveAsTextFile("output/testSaveAsTextFile")
// 序列化成对象保存到文件
source2.saveAsObjectFile("output/testSaveAsObjectFile")
// 保存成 SequenceFile 文件
source1.map((_,1)).saveAsSequenceFile("output/testSaveAsSequenceFile")
}
note:
saveAsSequenceFile() 方法要求数据必须为 K-V 键值对类型
foreach
函数签名
def foreach(f: T => Unit): Unit = withScope {
val cleanF = sc.clean(f)
sc.runJob(this, (iter: Iterator[T]) => iter.foreach(cleanF))
}
函数说明
分布式遍历RDD中的每一个元素,调用指定函数;是Driver端内存集合的循环遍历集合方法
@Test
def testForeach(): Unit = {
//收集后打印
source.collect().foreach(println)
//分布式打印
source.foreach(println)
}
note:
①使用collect算子,是先将数据按照分区进行采集,然后进行打印输出,这是在Driver端内存中的输出;
而直接使用foreach算子,实际上是在Executor端分布式打印 输出,并不是按照顺序采集再打印输出的。
②由于Driver和Executor是两个不同的结构,RDD 的方法外部的操作都是在Driver端执行的,而方法内部的逻辑代码是在Executor端执行的,以在进行数据传输之前需要先对类序列化操作样例类case class XX 在编译过程中会自动序列化,所以这也是主动继承序列化类以外的一种方法。
e.g.
code:
val source: RDD[Int] = sc.makeRDD(List(2, 1, 3, 4))
def main(args: Array[String]): Unit = {
val user = new test()
val user1 = new User()
println()
source.foreach(num => {
print("age:" + (user.age + num)+" ")
println("age:" + (user1.age + num)+",")
})
sc.stop()
}
case class User(){
val age: Int =30
}
class test extends Serializable {
val age: Int = 30
result:
age:31 age:31,
age:32 age:32,
age:34 age:34,
age:33 age:33,