Hadoop + Jackson解析:ObjectMapper读取Object然后中断

时间:2014-11-07 14:04:58

标签: java json hadoop jackson recordreader

我正在与Jackson一起在Hadoop中实现JSON RecordReader。 到目前为止,我正在使用JUnit + MRUnit进行本地测试。 JSON文件各包含一个对象,在一些标题之后,它有一个字段,其值是一个条目数组,每个条目我都想被理解为一个记录(所以我需要跳过这些标题)。

我可以通过将FSDataInputStream推进到读取点来实现这一点。 在我的本地测试中,我执行以下操作:

fs = FileSystem.get(new Configuration());
in = fs.open(new Path(filename));
long offset = getOffset(in, "HEADER_START_HERE");       
in.seek(offset);

其中getOffset是一个函数,其中指向InputStream字段值开始的位置 - 如果我们查看in.getPos()值,则可以正常工作。

我正在阅读第一条记录:

ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readValue (in, JsonNode.class);

第一张唱片回来了。我可以使用mapper.writeValueAsString(actualObj)并且它已经读得很好,而且它是有效的。

直到这里很好。

所以我尝试迭代这些对象:

ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = null;
do {
    actualObj = mapper.readValue (in, JsonNode.class);
    if( actualObj != null) {
        LOG.info("ELEMENT:\n" + mapper.writeValueAsString(actualObj) );
    }
} while (actualObj != null) ;

它读取第一个,但随后它破了:

java.lang.NullPointerException: null
    at org.apache.hadoop.fs.BufferedFSInputStream.getPos(BufferedFSInputStream.java:54)
    at org.apache.hadoop.fs.FSDataInputStream.getPos(FSDataInputStream.java:57)
    at org.apache.hadoop.fs.ChecksumFileSystem$ChecksumFSInputChecker.readChunk(ChecksumFileSystem.java:243)
    at org.apache.hadoop.fs.FSInputChecker.readChecksumChunk(FSInputChecker.java:273)
    at org.apache.hadoop.fs.FSInputChecker.read1(FSInputChecker.java:225)
    at org.apache.hadoop.fs.FSInputChecker.read(FSInputChecker.java:193)
    at java.io.DataInputStream.read(DataInputStream.java:132)
    at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:340)
    at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:116)
    at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:197)
    at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:503)
    at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:365)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1158)

为什么会发生这种异常?

是否与本地阅读有关?

在重用ObjectMapper或其基础流时是否需要某种重置?

1 个答案:

答案 0 :(得分:0)

我设法解决了这个问题。万一有帮助:

首先,我使用的是Jackson 1.x最新版本。 似乎JsonParser一旦用InputStream实例化,它就会控制它。 因此,在使用readValue()时,一旦读取它(在内部调用_readMapAndClose(),它会自动关闭流。 您可以设置一个设置,告诉JsonParser不要关闭基础流。在创建JsonFactory

之前,您可以将其传递给JsonParser
JsonFactory f = new MappingJsonFactory();
f.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);

请注意,您有责任关闭流(在我的情况下是FSDataInputStream)。 所以,答案:

  • 为什么会发生这种异常?

因为解析器管理流,并在readValue()之后关闭它。

  • 是否与本地阅读有关?

没有

  • 在重用ObjectMapper或其底层流时是否需要某种重置?

没有。当使用Streaming API与类似ObjectMapper的方法混合时,您需要注意的是,有时映射器/解析器可能会控制底层流。请参阅JsonParser的Javadoc并查看每种阅读方法的文档以满足您的需求。