Java Hadoop+;Jackson解析:ObjectMapper读取对象,然后中断

Java Hadoop+;Jackson解析:ObjectMapper读取对象,然后中断,java,json,hadoop,jackson,recordreader,Java,Json,Hadoop,Jackson,Recordreader,我正在与Jackson一起在Hadoop中实现JSON RecordReader。 现在我正在使用JUnit+MRUnit进行本地测试。 JSON文件每个都包含一个对象,在一些头之后,它有一个字段,其值是一个条目数组,我希望每个条目都被理解为一条记录(因此我需要跳过这些头) 我可以通过将FSDataInputStream提升到读取点来实现这一点。 在本地测试中,我执行以下操作: fs = FileSystem.get(new Configuration()); in = fs.open(new

我正在与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指向字段值开始的位置-如果我们查看.getPos()中的
value,它工作正常

我正在通过以下方式阅读第一条记录:

ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = mapper.readValue (in, JsonNode.class);
第一张唱片恢复得很好。我可以使用
mapper.writeValueAsString(ActualLobj)
并且它读得很好,并且是有效的

在这里之前都很好

因此,我尝试通过执行以下操作来迭代对象:

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
或其底层流时是否需要某种重置或其他操作?

我设法解决了这个问题。如果有帮助:

首先,我使用的是Jackson 1.x的最新版本。 似乎一旦用
InputStream
实例化了
JsonParser
,它就会控制它。 因此,当使用
readValue()
时,一旦读取它(在内部调用
)\u readMapAndClose()
,它会自动关闭流。 您可以设置一个设置,告诉
JsonParser
不要关闭底层流。在创建
JsonParser
之前,您可以像这样将其传递给
JsonFactory

JsonFactory f = new MappingJsonFactory();
f.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
请注意,您负责关闭流(在我的情况下是FSDataInputStream)。 因此,答案如下:

  • 为什么会发生这种异常
因为解析器管理流,并在readValue()之后关闭它

  • 这与在当地阅读有关吗
没有

  • 重用ObjectMapper或其底层流时是否需要某种重置或其他操作

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

现在还有一个不错的新的
映射迭代器
可以通过
ObjectReader
(由
ObjectMapper
构造)获取,它允许您映射要迭代的值序列。它简化了操作,因此您无需使用
JsonParser
,而只需使用类似于
Mapping迭代器It=mapper.readerFor(JsonNode.class).readValues(src);