有关spark rdd.saveAsObjectFile

时间:2016-11-02 18:45:38

标签: apache-spark

Spark可以将rdd保存到rdd.saveAsObjectFile("file")的文件中。 我需要在Spark之外读取这个文件。根据{{​​3}},使用默认的spark序列化程序,此文件只是使用标准Java序列化序列化的一系列对象。但是,我猜该文件有一个标题和对象之间的分隔符。我需要读取此文件,并使用doc反序列化每个Java / Scala对象(因为我没有类定义)。

在哪里可以找到有关rdd.saveAsObjectFile("file")生成的文件格式的文档(使用标准序列化程序,而不是Kryo序列化程序)?

更新 基于VladoDemcak的工作示例回答:

import org.apache.hadoop.io._
import org.apache.hadoop.conf._
import org.apache.hadoop.fs._
import org.apache.hadoop.io._

def deserialize(data: Array[Byte]) =
  new ObjectInputStream(new ByteArrayInputStream(data)).readObject()

val path = new Path("/tmp/part-00000")
val config = new Configuration()
val reader = new SequenceFile.Reader(FileSystem.get(new Configuration()), path, config)
val key = NullWritable.get
val value = new BytesWritable

while (reader.next(key, value)) {
  println("key: {} and value: {}.", key, value.getBytes)
  println(deserialize(value.getBytes()))
}
reader.close()

1 个答案:

答案 0 :(得分:1)

这是一个非常有趣的问题,所以我将尝试解释我对这些工作人员的了解。您可以查看saveAsObjectFile以及我看到的有关详细信息is API javadoc

的文档
  /**
   * Save this RDD as a SequenceFile of serialized objects.
   */
  def saveAsObjectFile(path: String): Unit = withScope {
    this.mapPartitions(iter => iter.grouped(10).map(_.toArray))
      .map(x => (NullWritable.get(), new BytesWritable(Utils.serialize(x))))
      .saveAsSequenceFile(path)
  }

据我所知saveAsObjectFile生成SequenceFile。基于sequenceFile的文档,它的标题包含versionclassnamemetadata ...

  

有3种不同的SequenceFile格式:

     

未压缩的键/值记录。记录压缩的键/值记录 -   这里只压缩'值'。阻止压缩的键/值记录    - 键和值分别在'块'中收集并压缩。 “块”的大小是可配置的。

     

所有上述格式共享一个公共标题(由...使用)   SequenceFile.Reader返回相应的键/值对。

对于读取序列文件,我们可以使用hadoop SequenceFile.Reader实现。

Path path = new Path("/hdfs/file/path/seqfile");
SequenceFile.Reader reader = new SequenceFile.Reader(FileSystem.get(new Configuration()), path, config);
WritableComparable key = (WritableComparable) reader.getKeyClass().newInstance();
Writable value = (Writable) reader.getValueClass().newInstance();

while (reader.next(key, value)){
     logger.info("key: {} and value: {}.", key, value.getBytes());
     // (MyObject) deserialize(value.getBytes());
}

reader.close();

我没有对此进行测试,但根据您在问题中注意到的doc链接:

  

默认情况下,Spark使用Java的ObjectOutputStream序列化对象   框架

所以在循环中你可以得到值的字节,并用ObjectInputStream

反序列化
public static Object deserialize(byte[] data){
    return new ObjectInputStream(new ByteArrayInputStream(data)).readObject();
}

在你的情况下你需要在反序列化方法中使用你的库(jdeserialize) - 我猜run(InputStream is, boolean shouldConnect)等。