Spark Scala:任务不可序列化错误

时间:2017-04-24 15:58:01

标签: scala apache-spark pyspark

我正在使用带有Scala插件和spark库的IntelliJ社区版。我还在学习Spark并且正在使用Scala工作表。

我编写了以下代码,用于删除字符串中的标点符号:

def removePunctuation(text: String): String = {
  val punctPattern = "[^a-zA-Z0-9\\s]".r
  punctPattern.replaceAllIn(text, "").toLowerCase
}

然后我读了一个文本文件并尝试删除标点符号:

val myfile = sc.textFile("/home/ubuntu/data.txt",4).map(removePunctuation)

这会给出如下错误,任何帮助都将不胜感激:

  

org.apache.spark.SparkException:任务不可序列化       在org.apache.spark.util.ClosureCleaner $ .ensureSerializable(/home/ubuntu/src/main/scala/Test.sc:294)       在org.apache.spark.util.ClosureCleaner $ .org $ apache $ spark $ util $ ClosureCleaner $$ clean(/home/ubuntu/src/main/scala/Test.sc:284)       在org.apache.spark.util.ClosureCleaner $ .clean(/home/ubuntu/src/main/scala/Test.sc:104)       在org.apache.spark.SparkContext.clean(/home/ubuntu/src/main/scala/Test.sc:2090)       在org.apache.spark.rdd.RDD $$ anonfun $ map $ 1.apply(/home/ubuntu/src/main/scala/Test.sc:366)       在org.apache.spark.rdd.RDD $$ anonfun $ map $ 1.apply(/home/ubuntu/src/main/scala/Test.sc:365)       在org.apache.spark.rdd.RDDOperationScope $ .withScope(/home/ubuntu/src/main/scala/Test.sc:147)       在#worksheet#。#worksheet#(/ home / ubuntu / src / main / scala / Test.sc:108)   引起:java.io.NotSerializableException:A $ A21 $ A $ A21   序列化堆栈:        - 对象不可序列化(类:A $ A21 $ A $ A21,价值:A $ A21 $ A $ A21 @ 62db3891)        - 字段(类:A $ A21 $ A $ A21 $$ anonfun $ words $ 1,名称:$ outer,类型:A $ A21 $ A $ A21)        - 对象(A $ A21 $ A $ A21 $$ anonfun $ words $ 1,)       在org.apache.spark.serializer.SerializationDebugger $ .improveException(SerializationDebugger.scala:40)       在org.apache.spark.serializer.JavaSerializationStream.writeObject(JavaSerializer.scala:46)       在org.apache.spark.serializer.JavaSerializerInstance.serialize(JavaSerializer.scala:100)       在org.apache.spark.util.ClosureCleaner $ .ensureSerializable(ClosureCleaner.scala:295)       在org.apache.spark.util.ClosureCleaner $ .org $ apache $ spark $ util $ ClosureCleaner $$ clean(ClosureCleaner.scala:288)       在org.apache.spark.util.ClosureCleaner $ .clean(ClosureCleaner.scala:108)       在org.apache.spark.SparkContext.clean(SparkContext.scala:2094)       在org.apache.spark.rdd.RDD $$ anonfun $ map $ 1.apply(RDD.scala:370)       在org.apache.spark.rdd.RDD $$ anonfun $ map $ 1.apply(RDD.scala:369)       在org.apache.spark.rdd.RDDOperationScope $ .withScope(RDDOperationScope.scala:151)       在org.apache.spark.rdd.RDDOperationScope $ .withScope(RDDOperationScope.scala:112)       在org.apache.spark.rdd.RDD.withScope(RDD.scala:362)       在org.apache.spark.rdd.RDD.map(RDD.scala:369)       在A $ A21 $ A $ A21.words $ lzycompute(Test.sc:27)       在A $ A21 $ A $ A21.words(Test.sc:27)       at A $ A21 $ A $ A21.get $$ instance $$ words(Test.sc:27)       在A $ A21 $ .main(Test.sc:73)       在A $ A21.main(Test.sc)       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)       at java.lang.reflect.Method.invoke(Method.java:498)       在org.jetbrains.plugins.scala.worksheet.MyWorksheetRunner.main(MyWorksheetRunner.java:22)

3 个答案:

答案 0 :(得分:5)

正如T. Gaweda已经指出的那样,你最有可能在一个不可序列化的类中定义你的函数。因为它是一个纯函数,即它不依赖于封闭类的任何上下文,我建议你把它放到一个应该扩展Serializable的伴随对象中。这将是Scala相当于Java静态方法:

object Helper extends Serializable {
  def removePunctuation(text: String): String = {
    val punctPattern = "[^a-zA-Z0-9\\s]".r
    punctPattern.replaceAllIn(text, "").toLowerCase
  }
}

答案 1 :(得分:5)

正如@TGaweda所说,Spark的SerializationDebugger对于识别“从给定对象到有问题对象的序列化路径”非常有用。堆栈跟踪中“序列化堆栈”之前的所有美元符号表示方法的容器对象是问题。

虽然最容易在容器类上使用Serializable,但我更喜欢利用Scala是一种函数式语言并将您的函数用作一等公民的事实:

sc.textFile("/home/ubuntu/data.txt",4).map { text =>
  val punctPattern = "[^a-zA-Z0-9\\s]".r
  punctPattern.replaceAllIn(text, "").toLowerCase
}

或者,如果你真的想把事情分开:

val removePunctuation: String => String = (text: String) => {
  val punctPattern = "[^a-zA-Z0-9\\s]".r
  punctPattern.replaceAllIn(text, "").toLowerCase
}
sc.textFile("/home/ubuntu/data.txt",4).map(removePunctuation)

这些选项当然适用于Regex is serializable,因为您应该确认。

在次要但非常重要的说明中,构建Regex代价很高,因此为了提高性能而将其从转换中分解出来 - 可能使用broadcast

答案 2 :(得分:2)

阅读stacktrace,有:

  

$ outer,类型:A $ A21 $ A $ A21

这是一个非常好的提示。您的lambda是可序列化的,但您的类不可序列化。

当你创建lambda表达式时,这个表达式引用了外部类。您的案例中的外类不可序列化,即未实现Serializable或其中一个字段不是Serializable的实例