如何在Spark中的每个分区上找到总和

时间:2019-06-19 06:06:12

标签: scala apache-spark rdd partitioning

我已经创建了一个类,并使用该类来创建RDD。我想在每个分区计算 LoudnessRate 的总和(类的成员)。此总和随后将用于计算每个分区的均值 LoudnessRate 。 我尝试了以下代码,但它不计算总和,并返回 0.0 。 我的代码是

    object sparkBAT {
      def main(args: Array[String]): Unit = {
        val numPartitions = 3
        val N = 50
        val d = 5
        val MinVal = -10
        val MaxVal =  10
        val conf = new SparkConf().setMaster(locally("local")).setAppName("spark Sum")
        val sc = new SparkContext(conf)

        val ba = List.fill(N)(new BAT(d, MinVal, MaxVal))
        val rdd = sc.parallelize(ba, numPartitions)

        var arrSum =Array.fill(numPartitions)(0.0) // Declare Array that will hold sum for each Partition
        rdd.mapPartitionsWithIndex((k,iterator) => iterator.map(x => arrSum(k) += x.LoudnessRate)).collect()
        arrSum foreach println
      }
    }


    class BAT (dim:Int, min:Double, max:Double) extends Serializable {    
      val random = new Random()
      var position      : List[Double]      =   List.fill(dim) (random.nextDouble() * (max-min)+min )
      var velocity      :List[Double]       =   List.fill(dim)( math.random)
      var PulseRate     : Double            =   0.1
      var LoudnessRate  :Double             =   0.95
      var frequency     :Double             =   math.random
      var fitness       :Double             =   math.random
      var BestPosition  :List[Double]       =   List.fill(dim)(math.random)
      var BestFitness   :Double             =   math.random 
    }

2 个答案:

答案 0 :(得分:4)

根据要求将我的评论更改为答案。原始评论

  

您正在修改执行程序JVM中的arrSum,并在驱动程序JVM中打印其值。您可以将迭代器映射到单例迭代器,并使用collect将值移动到驱动程序。另外,请勿将iterator.map用作副作用,而iterator.foreach是为此目的而设计的。

这是一个示例代码片段。首先使用两个分区0 -> 1,2,31 -> 4,5创建一个RDD。当然,您在实际代码中将不需要此,但是随着sc.parallelize行为根据环境而变化,这将始终创建统一的RDD来重现:

object DemoPartitioner extends Partitioner {
  override def numPartitions: Int = 2
  override def getPartition(key: Any): Int = key match {
    case num: Int => num
  }
}
val rdd = sc
  .parallelize(Seq((0, 1), (0, 2), (0, 3), (1, 4), (1, 5)))
  .partitionBy(DemoPartitioner)
  .map(_._2)

然后是实际技巧:

val sumsByPartition = rdd.mapPartitionsWithIndex {
  case (partitionNum, it) => Iterator.single(partitionNum -> it.sum)
}.collect().toMap
println(sumsByPartition)

输出:

Map(0 -> 6, 1 -> 9)

答案 1 :(得分:0)

问题是您使用的是arrSum(常规集合),它在驱动程序中声明并在执行程序中更新。每当您这样做时,都需要使用累加器。

This应该有所帮助