将输入文件映射到不同的RDD

时间:2018-01-14 11:10:24

标签: scala apache-spark

我有一个由整数列组成的文本文件。假设我有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

感谢您解决此问题的任何帮助。

2 个答案:

答案 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必须将整个类实例发送给执行程序以访问这些字段,而我的类不可序列化。

我在方法中将所有全局字段复制为局部变量,因此只将局部变量发送给执行程序,问题就解决了。