Arrays 为什么我不能在集群模式下更新数组,但可以在伪分布式模式下更新
我用scala编写了一个spark程序,主要代码如下: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
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集群上,我不知道为什么这些代码只运行了两个外部历元。非常感谢您能帮助我处理这个错误。