Spark总结之RDD(七)

Spark总结之RDD(七)

1. 背景

  1. Spark作为大数据分布式处理引擎,在设计思想上很大参考了mapreduce的设计思想,但在编程便利性上做了更高层级的抽象,屏蔽了很多分布式计算的细节。具体体现在编程接口的抽象设计上,如RDD、dataSet、dataFrame、DStream等
  2. Spark本身分为SaprkCore,包含RDD、Accumulators、broadCast,以及内部运行机制,在此之上,有更高层级的抽象,如Spark SQL、Spark Streaming、MLib、Graphx等四大部分,分别是sql、流式处理、机器学习、图计算。
  3. http://spark.apache.org/
    在这里插入图片描述
  4. RDD属于Spark最基础的计算抽象,更上层的编程本质还是转换为RDD来处理,RDD再转换为物理执行计划,分布式运行。

2. 案例

  1. 本文是关于分布式累加器的文章,实际生产中,有时候需要对数据做统计,这时候可以使用类似过滤器,count等操作组合做统计.
  2. spark还提供了accumulator分布式累加器来提供更便捷功能.

2.1 longAccumulator

  1. 顾名思义,这是对于整数的累加器,可以对整数进行累加.
  2. 实际使用时,可以根据需要累加1,也可以累加其他数字.
  3. 注意,这里的本质是闭包,是一个class,每个task都会有一个自己的累加器对象,最后的结果是这些累加器汇总到一起之后的结果
  4. 在spark的分布式计算中,如果使用闭包,最后在executor进行反序列化时会有2种结果,一种是class,这时候一般是一个task一个实例.因为task最终是在executor的线程池中在线程中执行的;一种是object,这时候executor中是只会反序列化一个单例对象(scala的object就是静态对象,只有一个)
  5. 代码
object AccumulatorTest1 {
  def main(args: Array[String]): Unit = {

    val conf: SparkConf = new SparkConf().setAppName("AccumulatorTest1").setMaster("local")

    val sc = new SparkContext(conf)

    val rdd1: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9))

    val longAcc: LongAccumulator = sc.longAccumulator("longAcc")

    rdd1.foreach(ele=>{
      if(ele % 2 == 0) {
        longAcc.add(1L)
      }
    })

    val count: Long = longAcc.count
    val value: lang.Long = longAcc.value

    println(count)
    println(value)

    sc.stop()
  }
}

运行结果

4
4

2.2 doubleAccumulator

  1. 代码
object AccumulatorTest2 {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("AccumulatorTest1").setMaster("local")

    val sc = new SparkContext(conf)

    val rdd1: RDD[Double] = sc.parallelize(List(1.1, 2.2, 3.3, 4.4, 5.5))

    val doubleAcc: DoubleAccumulator = sc.doubleAccumulator("doubleAcc")

    // 累加器并不会影响数据要做的操作,只是做数据统计
    val resRDD: RDD[Double] = rdd1.map(ele => {
      if (ele > 3) {
        doubleAcc.add(ele)
      }

      ele + 10
    })

    println(resRDD.collect().toBuffer)

    println("value: " + doubleAcc.value)
    println("count: " + doubleAcc.count)

    sc.stop()
  }
}

运行结果

ArrayBuffer(11.1, 12.2, 13.3, 14.4, 15.5)
value: 13.2
count: 3
  1. 源码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

2.3 collectionAccumulator

  1. 实际生产中,如果需要对数据做统计汇总,并且拿回来,这时候一般使用这个集合累加器,可以将所需要的数据以集合形式取回
  2. 注意,所有的累加器最后都是会返回到driver端的内存中,所以累加器不适合存储大量数据,顾名思义,适合进行数据累加
  3. 如果真的需要对数据做大量统计汇总,可以使用日志或者文件工具,将这些数据写入到文件,数据库或者hdfs中.
object AccumulatorTest3 {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("AccumulatorTest1").setMaster("local")

    val sc = new SparkContext(conf)

    val rdd1: RDD[Any] = sc.parallelize(List(1.1, "20", 2.2, "30", 3.3, "40", 4.4, "50", 5.5))

    val collectionAcc: CollectionAccumulator[String] = sc.collectionAccumulator[String]("collectionAcc")

    val resRDD: RDD[String] = rdd1.map(ele => {
      if (ele.isInstanceOf[String]) {
        collectionAcc.add(ele.asInstanceOf[String])
      }

      ele.toString
    })

    println(resRDD.collect().toBuffer)

    val accValue: util.List[String] = collectionAcc.value

    import scala.collection.JavaConverters._
    for(e <- accValue.asScala){
      println(e)
    }

    sc.stop()
  }
}

运行结果

ArrayBuffer(1.1, 20, 2.2, 30, 3.3, 40, 4.4, 50, 5.5)
20
30
40
50
  1. 源码
    在这里插入图片描述
    在这里插入图片描述

可以看到,这是class,在使用时,在driver端创建,但实际执行是在executor端执行,所以形成了一个闭包
注意,在分布式计算中,如果要做数据做处理,可以一个executor中创建一个对象,多个task共享这个对象来做处理,但这样就需要加锁
但更有效的一种方式就是分布式思想,每个task有自己的对象,最终结果就是所有task的结果进行汇总.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值