Action行动算子---聚合、统计key数、save算子讲解(上)

205 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

因为Transformation转换算子都是懒加载,并不会立即执行,只有遇到行动算子才会触发整个作业的执行。Action行动算子大体上可以分为 聚合算子、统计key数算子、save算子、返回数据集算子、遍历算子,我分上下两篇进行讲解,上篇讲 聚合算子、统计key数算子、save算子。

聚合算子

行动算子中的聚合算子其实类似于 之前我们说过的 转换算子中的聚合,比如 reduceByKey,aggregateByKey、foldByKey,但与之不同的是,action中的算子可以立即执行,所以我们最后只需要打印结果就好,不用像转换算子还需要用到遍历打印。

(1)reduce()

def reduce(f: (T, T) => T): T

功能:f 函数聚集RDD中的所有元素,先聚合分区内数据,再聚合分区间数据。

依然是我们通过图示来明确算子的功能,然后通过代码实际应用。创建一个RDD,我们将所有元素聚合得到结果

image.png

代码如下:

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 ,将所有元素相加得到结果,图示如下:

image.png

注意: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的个数

image.png

代码如下:

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()
  }
}