《Spark 5》--RDD 的 行动操作

本文详细介绍了Spark中RDD的行动操作,包括first(), count(), reduce(), collect(), take(), top(), takeOrdered(), sortBy(), foreach()以及aggregate()和fold()。重点讨论了这些操作的惰性求值特性、触发Job的条件,以及在不同模式下的行为差异,同时通过实例演示了如何使用这些操作进行数据处理和聚合。" 46865201,2865447,ArcGIS影像分类:最大似然法与监督、非监督分类,"['GIS', 'ArcGIS教程', '分类算法', '遥感']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

行动操作:

  惰性求值:【RDD的特性】
-------------------------------------------------------------------------------------------------------------------
    在RDD行动操作之前,不触发计算。转换操作和创建操作、控制操作均为惰性的;
    只有行动操作可触发Job。

-------------------------------------------------------------------------------------------------------------

    定义:触发Job,调用runJob()方法:
    比如:collect、count
       
    1.first():T 表示返回RDD中的第一个元素,不排序
    2.count(): Long表示返回RDD中的元素个数
    3.reduce(f:(T,T)=>T):T根据映射函数f,对RDD中的元素进地二元计算
    4.collect():Array[T]表示将RDD转换成数组
    
    5.take(num:Int)Array[T]表示获取RDD中从0到num-1下标的元素,不排序

 scala> var rdd1 = sc.makeRDD(Seq(10,4,3,12,3))
   rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[4] at makeRDD at 
   <console>:24

 scala> rdd1.take(1)
   res7: Array[Int] = Array(10)

    6.top(num:Int)Array[T]表示从RDD中,按照默认(降序)或者指定的排序规则,返回前num个元素
    scala> rdd1.top(3)
    res8: Array[Int] = Array(12, 10, 4)                                             

    7.takeOrdered(num:Int):Array[T]和top类似,只不过以和top相反的顺序返回元素
    scala> rdd1.takeOrdered(3)
    res9: Array[Int] = Array(3, 3, 4)
    
    8.sortBy[K](f:(T))=>K 定义RDD为键值类型
    scala> var rdd1 = sc.makeRDD(Array(("A",2),("A",1),("B",6),("B",3),("B",7)))
    rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[7] at makeRDD at <console>:24
    
    按照键值升序
    scala> rdd1.sortBy(x=>x).collect
    res10: Array[(String, Int)] = Array((A,1), (A,2), (B,3), (B,6), (B,7))          
    
    值降序排列
    scala> rdd1.sortBy(x=>x._2,false).collect
    res13: Array[(String, Int)] = Array((B,7), (B,6), (B,3), (A,2), (A,1))

    
    9.foreach
    说明:将结果返回值给执行器节点,而非驱动器,
    Local模式下:
    $ > spark-shell 
    scala> val a = sc.parallelize(List("dog", "tiger", "lion", "cat", "spider", "eagle"), 2)
    a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[6] at parallelize at <console>:24

    查看打印结果:
    scala> a.foreach(println)
    dog
    tiger
    lion
    cat
    spider
    eagle
    scala> :q

    $> spark-shell --master spark://master:7077
    scala> val a = sc.parallelize(List("dog", "tiger", "lion", "cat", "spider", "eagle"), 2)
    a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[0] at parallelize at <console>:24

    scala> a.foreach(println)
    无结果:
    
    查看master:4040
    Running Applications-->Executor Summary-->Logs --> stdout log page for app-20190727155306-0007/2  cat spider eagle
    
    总结:
    spark-shell【本地模式】 下所有的守护进程在一个JVM中,所以可以使用foreach
    
    打印RDD的元素:
    另一个常见的习惯用法是尝试使用rdd.foreach(println)或打印出RDD的元素rdd.map(println)。
    在一台机器上,这将生成预期的输出并打印所有RDD的元素。
    但是,在cluster模式下,stdout执行程序调用的输出先写入执行stdout程序,
    而不是驱动程序上的输出,因此stdout驱动程序不会显示这些!要打印驱动程序上的所有元素,
    可以使用该collect()方法首先将RDD带到驱动程序节点:rdd.collect().foreach(println)。
    但是,这会导致驱动程序内存不足,因为collect()将整个RDD提取到一台机器上; 
    如果您只需要打印RDD的一些元素,更安全的方法是使用take():rdd.take(100).foreach(println)
    
    
    10.aggregate
       def aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
       说明:aggregate用于聚合RDD中的元素,先使用seqOp将RDD中每个分区中的T类型元素聚合成U类型,
                  再使用combOp将之前每个分区聚合后的U类型聚合成U类型
                  特别注意seqOp和combOp都会使用zeroValue的值,zeroValue的类型为U
        val z = sc.parallelize(List(1,2,3,4,5,6), 2)
        z.aggregate(0)(math.max(_, _), _ + _) 
        
        res40: Int = 9
        说明:
        step1:首先在第一个分区[0,1,2,3]中执行math.max,结果为:3
        step2:在第二个分区[0,4,5,6]中执行math.max,结果为:6
        stepn:在第N个分区中执行math.max,结果为:max
        step:将所有分区结果执行combOp(_+_),0+3+6=9
    
    修改初值为5:    
    z.aggregate(5)(math.max(_, _), _ + _)
    
    结果是多少?
    
    
    说明:
        // This example returns 16 since the initial value is 5
        // reduce of partition 0 will be max(5, 1, 2, 3) = 5
        // reduce of partition 1 will be max(5, 4, 5, 6) = 6
        // final reduce across partitions will be 5 + 5 + 6 = 16
        // note the final reduce include the initial value
    
    
    案例说明:
    scala> val z = sc.parallelize(List("12","23","345","4567"),2)
    z: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[3] at parallelize at <console>:24

    scala> z.glom.collect
    res11: Array[Array[String]] = Array(Array(12, 23), Array(345, 4567))

    scala> z.aggregate("")((x,y) => math.max(x.length, y.length).toString, (x,y) => x + y)
    
    res12: String = 42

    scala> z.aggregate("")((x,y) => math.max(x.length, y.length).toString, (x,y) => x + y)
    res13: String = 24
    
        说明:
         step1:第一个分区中执行math.max(x.length, y.length).toString代码
            res0=:math.max(“”.length, “12”.length).toString = “2”
            res1=:math.max(res0.length, “23”.length).toString = “2”
            第一个分区最终返回值为:2
         step2:第二个分区中执行math.max(x.length, y.length).toString代码
            res2=:math.max(“”.length, “345”.length).toString = “3”
            res3=:math.max(res2.length, “4567”.length).toString = “4”
            第一个分区最终返回值为:4
         step3:最后执行(x,y) => x + y   :24  或  42 
            【原因分区是在不同的executor下运行,查看webUI task执行的秒数】
            
    scala> z.aggregate("")((x,y) => math.min(x.length, y.length).toString, (x,y) => x + y)
           res14: String = 11
         
            step1:第一个分区中执行math.min(x.length, y.length).toString代码
            res0=:math.min(“”.length, “12”.length).toString = “0”
            res1=:math.min(res0.length, “23”.length).toString = “1”
            第一个分区最终返回值为:1
         step2:第二个分区中执行math.min(x.length, y.length).toString代码
            res2=:math.min(“”.length, “345”.length).toString = “0”
            res3=:math.min(res2.length, “4567”.length).toString = “1”
            第一个分区最终返回值为:1
         step3:最后执行(x,y) => x + y   :11  或 11
         
    scala> z.aggregate("12")((x,y) => math.min(x.length, y.length).toString, (x,y) => x + y)
    
    res15: String = 1211
            step1:第一个分区中执行math.min(x.length, y.length).toString代码
            res0=:math.min(“12”.length, “12”.length).toString = “2”
            res1=:math.min(res0.length, “23”.length).toString = “1”
            第一个分区最终返回值为:1
         step2:第二个分区中执行math.min(x.length, y.length).toString代码
            res2=:math.min(“12”.length, “345”.length).toString = “2”
            res3=:math.min(res2.length, “4567”.length).toString = “1”
            第一个分区最终返回值为:1
         step3:最后执行(x,y) => x + y   :1211  或 1211
         
    11.fold
        def fold(zeroValue: T)(op: (T, T) => T): T
        说明:fold理解为aggregate的简化
     val a = sc.parallelize(List(1,2,3), 3)
     a.fold(0)(_ + _)
     res59: Int = 6

     12.reduceByKeyLocally
        该函数将RDD[K,V]中每个K对应的V值根据映射函数来运算,运算结果映射到一个Map[K,V]中,而不是RDD[K,V]
    def reduceByKeyLocally(func: (V, V) => V): Map[K, V]
    scala> val a = sc.parallelize(List("dog", "cat", "owl", "gnu", "ant"), 2)
    a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[0] at parallelize at <console>:24

    scala> val b = a.map(x => (x.length, x))
    b: org.apache.spark.rdd.RDD[(Int, String)] = MapPartitionsRDD[1] at map at <console>:26
    
    scala> b.glom.collect
    Array[Array[(Int, String)]] = Array(Array((3,dog), (3,cat)), Array((3,owl), (3,gnu), (3,ant)))    
    
    scala> b.reduceByKeyLocally(_+_)
    res0: scala.collection.Map[Int,String] = Map(3 -> dogcatowlgnuant) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值