Arrays 为什么我不能在集群模式下更新数组,但可以在伪分布式模式下更新

Arrays 为什么我不能在集群模式下更新数组,但可以在伪分布式模式下更新,arrays,scala,apache-spark,Arrays,Scala,Apache Spark,我用scala编写了一个spark程序,主要代码如下: val centers:Array[(Vector,Double)] = initCenters(k) val sumsMap:Map(int,(vector,int))= data.mapPartitions{ *** }.reduceByKey(***).collectAsMap() sumsMap.foreach{case(index,(sum,count))=> sum/=count centers(ind

我用scala编写了一个spark程序,主要代码如下:

val centers:Array[(Vector,Double)] = initCenters(k)
val sumsMap:Map(int,(vector,int))= data.mapPartitions{
    ***
}.reduceByKey(***).collectAsMap()
sumsMap.foreach{case(index,(sum,count))=>
   sum/=count
   centers(index)=(sum,sum.norm2())
}
原产地代码为:

 val centers = initCenters.getOrElse(initCenter(data))

val br_centers = data.sparkContext.broadcast(centers)
val trainData = data.map(e => (e._2, e._2.norm2)).cache()
val squareStopBound = stopBound * stopBound
var isConvergence = false
var i = 0
val costs = data.sparkContext.doubleAccumulator

while (!isConvergence && i < maxIters) {
  costs.reset()
  val res = trainData.mapPartitions { iter =>
    val counts = new Array[Int](k)
    util.Arrays.fill(counts, 0)
    val partSum = (0 until k).map(e => new DenseVector(br_centers.value(0)._1.size))

    iter.foreach { e =>
      val (index, cost) = KMeans.findNearest(e, br_centers.value)
      costs.add(cost)
      counts(index) += 1
      partSum(index) += e._1
    }
    counts.indices.filter(j => counts(j) > 0).map(j => (j -> (partSum(j), counts(j)))).iterator
  }.reduceByKey { case ((s1, c1), (s2, c2)) =>
    (s1 += s2, c1 + c2)
  }.collectAsMap()
  br_centers.unpersist(false)


  println(s"cost at iter: $i is: ${costs.value}")
  isConvergence = true
  res.foreach { case (index, (sum, count)) =>
    sum /= count
    val sumNorm2 = sum.norm2()
    val squareDist = math.pow(centers(index)._2, 2.0) + math.pow(sumNorm2, 2.0) - 2 * (centers(index)._1 * sum)
    if (squareDist >= squareStopBound) {
      isConvergence = false
    }
    centers.update(index,(sum, sumNorm2))
  }
  i += 1
}
在IDEA中以伪分布式模式运行时,我会更新中心,而在spark群集上运行时,我不会更新中心。

请查看编程指南中的部分


Spark是一个分布式系统,您所展示的代码的行为完全是未定义的。它在本地模式下工作纯属偶然,因为它在单个JVM中执行所有操作。

LostInOverflow的回答是正确的,但并不是特别描述发生了什么

以下是代码的一些重要属性:

声明一个数组中心 以br_中心广播此阵列 迭代更新中心 这是怎么回事?嗯,广播是静态的。如果我写:

val a = Array(1,2,3)
val aBc = sc.broadcast(a)
a(0) = 67
访问aBc.value0,我将得到不同的结果,这取决于此代码是否在驱动程序JVM上运行。广播接收一个对象,将其通过网络传输到每个节点,并在每个JVM中创建一个新引用。此引用与广播基本对象时一样存在,并且在更改基本对象时不会实时更新

解决办法是什么?我认为在while循环中移动广播,以便广播更新的中心应该可以工作:

while (!isConvergence && i < maxIters) {
  val br_centers = data.sparkContext.broadcast(centers)
  ...

这不会改变答案。您通过闭包修改变量捕获,但它不受支持。是否在群集模式下出现序列化异常?或者你得到了什么例外?@PrudviSagar也不例外get@LostInOverflow请注意,sumsMap是master上的地图,而不是RDD。您的问题中没有足够的信息来回答它。请提供lambdas@TimP非常感谢您的关注,这是一个K-Means算法,我无法从这些代码中得到正确的结果。您得到的错误是什么?从未执行以res.foreach开头的代码块?我怀疑数组中心的更新没有成功。因为代码已经运行了外部迭代的两个历元,我认为res.foreach已经执行了。在spark集群上,我不知道为什么这些代码只运行了两个外部历元。非常感谢您能帮助我处理这个错误。