我有一个由整数列组成的文本文件。假设我有N列,我需要N-1个PairRDD。每个PairRDD将我文件的0到N-2列之一作为Key,最后一列作为Value。每次运行程序时,我的文件中的列数都会有所不同,所以在运行之前我不知道RDD的数量。
以下代码会导致import static java.util.stream.Collectors.toList;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
错误。
task not serializable
感谢您解决此问题的任何帮助。
答案 0 :(得分:2)
将您在调用类之外执行的操作移动到序列化类或对象:
class RDDOperation extends Serializable {
def perform(inputFile: RDD[String], numberOfColumns: Int) = {
for (dim <- 0 to (numberOfColumns - 2)) yield {
inputFile.map(line => {
val lines = line.split(',')
(lines(dim), lines(numberOfColumns - 1))
})
}
}
}
异常的原因是RDD的元素在群集的节点之间进行了分区。因此,当我们在RDD上使用map / flatMap时,所有操作都发生在多个节点上,因此必须序列化在map中执行的操作。因此,将其移动到序列化类或对象将使其序列化。
并且更喜欢在scala函数中返回值,因此我在这里使用了yield,它将返回pairRDD的集合。
另外,你可以重构不依赖于numberOfColumns的perform方法,如下所示:
def perform(inputFile: RDD[String]): RDD[(String, String)] = {
inputFile.flatMap{ line =>
val lines = line.split(',').toList
lines.reverse match {
case lastColumn :: _ => lines.flatMap{
case column if column != lastColumn => Some((column, lastColumn))
case _ => None
}
case _ => List.empty[(String, String)]
}
}
}
答案 1 :(得分:1)
在我的代码中,我引用了类的全局字段。因此,Spark必须将整个类实例发送给执行程序以访问这些字段,而我的类不可序列化。
我在方法中将所有全局字段复制为局部变量,因此只将局部变量发送给执行程序,问题就解决了。