org.apache.spark.SparkException: Task not serializable

          报错问题截取部分如下两句:           
  Exception in thread "main" org.apache.spark.SparkException: Task not serializable

  Caused by: java.io.NotSerializableException: org.apache.spark.SparkContext
      

查阅网上资料发现应该是对RDD进行操作时引用了类的成员变量而该成员变量无法被序列化

      测试代码如下:

object Test2 extends App{
   val conf = new SparkConf().setAppName("RVM").setMaster("local")
   val sc = new SparkContext(conf)
   val matrix = new DenseMatrix(2,2,Array(1.0,2,3,4))
   new Test(sc,matrix).run()

}

class Test(scc:SparkContext,PHI:DenseMatrix) extends Serializable{
   val ts = 0.1
   def run(): Unit ={
      val rdds = scc.parallelize(0 to 3)
      val a = rdds.map(
         x =>{
            PHI.toArray.apply(x)*x
         }
      )
      a.collect.foreach(println(_))
   }
}
       这一串代码运行确实会报错,而且报错如预期一样,最开始以为是因为DenseMatrix不能序列化导致的,结果将DenseMatrix换成了其它类型如Double等基本类型同样会报错,然后发现是scc(SparkContext)不能序列化导致的错误。

      解决办法是在不能序列化的变量前添加注释@transient告诉编译器该变量不需要进行序列化。网上还有其它的一些处理方法暂时未深入研究,如若此方法不行可以自行查阅。参考博客:http://www.cnblogs.com/zwCHAN/p/4305156.html

      补充: 再次遇到此BUG,代码如下:

        println(PHIVRddTest.collect().apply(0).toArray.apply(0))

         val PHIVRdd = varyArrayRdd.mapPartitions(
          x =>{
            val result = List[DenseMatrix]()
            val PHIV2 = f.DonetMulMatrix(PHI,new DenseMatrix(r,1,x.toArray.apply(0)).multiply(new DenseMatrix(1,c,onesArray.toArray)))
            result.::(PHIV2).iterator
          }
        )

在网上找的解答貌似不是很适用,报错部分说的是

Caused by java.io.NotSerializableException:java.lang.Object
上述代码类f是一个工具类,里面有我定义了的各种常用方法,PHI是一个矩阵,问题出在类f和矩阵PHI上,我只需要把上述一行PHIV2的部分修改为如下则就没问题了:

val PHIV2 = new FunctionsList().DonetMulMatrix(new DenseMatrix(r,c,PHIArrsT),new DenseMatrix(r,1,x.toArray.apply(0)).
multiply(new DenseMatrix(1,c,onesArray.toArray)))

可是我在上述贴出来的代码中类f是已经继承了Serializable的,实在是有点费解,希望有了解解决办法的指点一二。

不过针对此类这种问题找到了自己的一个折中的办法,就是不直接在对RDD的操作中用PHI,而是在外部先将PHI分解,获取到行列以及数组信息(eg: r = PHI.numRows),然后在RDD操作中用这些数据进行操作,这样就可以避免PHI无法被序列化的问题了。

     总结一下遇到这类问题有三种情况以及对应解决办法:

    (1)报错Caused by:XXX,如果提示的未序列化的XXX是类似与SparkContext这类只允许有一个不能重新申明的变量,则可以尝试在变量前面添加@transient

    (2)报错Caused by:XXX,如果提示的未序列化的XXX是某一个自定义的类,则注意是否继承了Serializable,没有就extends Serializable。如果是类似工具类中的方法和我上面一样序列化了还是报错则尝试直接在内部new这个类调用里面的方法吧

    (3)报错Caused by:XXX,如果提示的未序列化的XXX是某一个变量可以进行加工处理,如本人遇到的矩阵无法被序列化,而且因为它是其它类传递过来的参数可以进行处理提取数据,这种情况先在外部对数据处理得到各种基础类型如Double,Int,或者数组等,然后将这些基本类型带入RDD操作中。


猜你喜欢

转载自blog.csdn.net/klordy_123/article/details/50346119