我正在使用Scala for Spark中的一些基本矩阵运算。我不断得到记忆和堆错误,这些都是我不能期望和不理解的。
我试图实现一种方法,将矩阵乘以一个向量,然后减去另一个向量。我正在查看5000行和1,000,000列的矩阵。矩阵是稀疏的,但矢量是密集的,数据类型是双精度的。我使用的是Scala 2.10.4和Spark 1.4.1,但如果其他东西能更好用,那么这些版本并不重要。
import org.apache.spark.mllib.linalg.{DenseVector, Vector => SparkVector}
import org.apache.spark.mllib.linalg.distributed.IndexedRowMatrix
import org.apache.spark.rdd.RDD
import org.apache.spark.storage.StorageLevel
// "Axmy" means A times x minus y
def Axmy(A: IndexedRowMatrix, x: SparkVector, y: SparkVector): SparkVector = {
require(A.numCols == x.size)
require(A.numRows == y.size)
val p: RDD[Double] = A.rows.map(r => {
r.vector.toArray.zip(x.toArray).map({ case (aj, xj) => aj + xj })
.sum - y(r.index.toInt)
})
new DenseVector(p.collect)
}
如果没有这个工作,我会更多地考虑它,并意识到一行中所有1,000,000个元素需要同时存在于内存中,这可能会导致问题。我见过另一个关于矩阵转置的例子,所以我尝试实现自己的版本:
//ATxmy means Atranspose times x minus y
def ATxmy(AT: IndexedRowMatrix, x: SparkVector, y: SparkVector): SparkVector {
require(AT.numRows == x.size)
require(AT.numCols == y.size)
val p1: RDD[(Long, SparkVector)] = AT.rows.map(r => (r.index, r.vector))
p1.persist(StorageLevel.MEMORY_AND_DISK)
val p2: RDD[((Long, SparkVector), Double)] = p1.map({ case (ri, r) => ((ri, r), x(ri.toInt)) })
p2.persist(StorageLevel.MEMORY_AND_DISK)
val p3: RDD[Array[Double]] = p2.map({ case ((ri, r), v) => r.toArray.map(e => e * v) })
p3.persist(StorageLevel.MEMORY_AND_DISK)
val p4: Array[Double] = p3.reduce((a1, a2) => a1.zip(a2).map({ case (ae1, ae2) => ae1 + ae2 }))
val p5: Array[Double] = p4.zip(y.toArray).map({ case (axme, ye) => axme - ye })
new DenseVector(p5)
}
如果没有持续的调用,我在使用spark.master = local [*]的笔记本电脑和我公司的三节点集群上都会出现各种内存耗尽错误,驱动程序和执行程序内存设置为5G。最新的是" org.apache.spark.shuffle.FetchFailedException:直接缓冲内存"信息。随着调用持续,它似乎运行时间更长,但最终遇到了一个" IllegalArgumentException:大小超过Integer.MAX_VALUE" sun.nio.ch.FileChannelImpl.map中的消息,它似乎与分区大小有关。
Spark Java Error: Size exceeds Integer.MAX_VALUE
对于8字节的双精度数,5000个元素的数组应该只占用40 Kb的内存。显然,Spark会在内存中同时保留很多行的转置矩阵,这会导致内存耗尽问题,那么如何在需要完成计算时鼓励Spark更换内存和磁盘?现在我正在寻找可以工作的东西,以后可以优化。
提前致谢!