持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情
因为Transformation转换算子都是懒加载,并不会立即执行,只有遇到行动算子才会触发整个作业的执行。Action行动算子大体上可以分为 聚合算子、统计key数算子、save算子、返回数据集算子、遍历算子,我分上下两篇进行讲解,上篇讲 聚合算子、统计key数算子、save算子。
聚合算子
行动算子中的聚合算子其实类似于 之前我们说过的 转换算子中的聚合,比如 reduceByKey,aggregateByKey、foldByKey,但与之不同的是,action中的算子可以立即执行,所以我们最后只需要打印结果就好,不用像转换算子还需要用到遍历打印。
(1)reduce()
def reduce(f: (T, T) => T): T
功能:f 函数聚集RDD中的所有元素,先聚合分区内数据,再聚合分区间数据。
依然是我们通过图示来明确算子的功能,然后通过代码实际应用。创建一个RDD,我们将所有元素聚合得到结果
代码如下:
object action_reduce {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[Int] = sc.makeRDD(List(1,2,3,4))
//3.2 聚合数据
val reduceResult: Int = rdd.reduce(_+_)
println(reduceResult) //这里直接打印就可以出结果,可以看下transformation算子的代码
//4.关闭连接
sc.stop()
}
}
(2)aggregate()
def aggregate[U: ClassTag](zeroValue: u)(seqOp:(u,T) => U, combOp:(u,U)=> U): U
功能: aggregate函数将每个分区里面的元素通过分区内逻辑和初始值进行聚合,然后用分区间逻辑和初始值(zeroValue)进行操作。每一个参数的解释类似于转换算子中的 aggregateByKey,不懂的可以看我文章juejin.cn/post/715454… ,这里不再过多赘述。
创建一个RDD ,将所有元素相加得到结果,图示如下:
注意:aggregate()算子在进行分区间的逻辑运算时会再次使用一次初始值,这是不同于转换算子中的aggregateByKey()。
代码如下:
object action_aggregate {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 8)
//3.2 将该RDD所有元素相加得到结果
val result: Int = rdd.aggregate(10)(_ + _, _ + _)
println(result)
//4.关闭连接
sc.stop()
}
}
(3)fold()
def fold(zeroValue:T)(op:(T,T)=> T):T
功能:aggregate的简化操作,分区内运算逻辑和分区间运算逻辑相同
代码如下:
object action_fold {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))
//3.2 将该RDD所有元素相加得到结果
val foldResult: Int = rdd.fold(0)(_+_) //分区内和分区间都是加法运算
println(foldResult)
//4.关闭连接
sc.stop()
}
}
统计Key个数
countByKey()
def countByKey(): Map[K, Long]
功能:统计每种key的个数
代码如下:
object action_countByKey {
def main(args: Array[String]): Unit = {
//1.创建SparkConf并设置App名称
val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")
//2.创建SparkContext,该对象是提交Spark App的入口
val sc: SparkContext = new SparkContext(conf)
//3具体业务逻辑
//3.1 创建第一个RDD
val rdd: RDD[(Int, String)] = sc.makeRDD(List((1, "a"), (1, "a"), (1, "a"), (2, "b"), (3, "c"), (3, "c")))
//3.2 统计每种key的个数
val result: collection.Map[Int, Long] = rdd.countByKey()
println(result)
//4.关闭连接
sc.stop()
}
}
save相关算子
1)saveAsTextFile(path): 保存成Text文件
功能:将数据集的元素以 textfile 的形式保存到 HDFS文件系统 或者 其他支持的文件系统,对于每个元素,Spark将会调用 toString方法,将它转换为文件中的文本
2)saveAsSequenceFile(path): 保存成Sequencefile文件
功能:将数据集中的元素以 Hadoop Sequencefile 的格式保存到 指定的目录下,可以使 HDFS 或者 其他Hadoop支持的文件系统。
注意: 至于 kv类型的RDD有该操作,单值的没有。
3)saveAsObjectFile(path): 序列化成对象保存到文件
功能说明: 用于将RDD中的元素序列化为对象,存储到文件中。
save算子代码如下
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object action_Save {
def main(args: Array[String]): Unit = {
// 1. 创建配置对象
val conf: SparkConf = new SparkConf().setAppName("sparkCore").setMaster("local[*]")
// 2. 初始化sc
val sc = new SparkContext(conf)
// 3. 编写代码
// (1)保存文本文件 能够直接读懂, 对于所有格式的rdd都能用
val intRDD: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
intRDD.saveAsTextFile("output")
// (2)保存二进制文件 只能用于二元组的rdd
val rdd = sc.makeRDD(List(("a",1),("b",5),("a",5),("b",2)),2)
rdd.saveAsSequenceFile("output1")
// (3)保存对象文件
// 将数据作为代码中的对象进行保存的 -> 能够保存自定义的类
intRDD.saveAsObjectFile("output2")
// 4.关闭sc
sc.stop()
}
}