Java Hadoop+;Jackson解析:ObjectMapper读取对象,然后中断
我正在与Jackson一起在Hadoop中实现JSON RecordReader。 现在我正在使用JUnit+MRUnit进行本地测试。 JSON文件每个都包含一个对象,在一些头之后,它有一个字段,其值是一个条目数组,我希望每个条目都被理解为一条记录(因此我需要跳过这些头) 我可以通过将FSDataInputStream提升到读取点来实现这一点。 在本地测试中,我执行以下操作: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
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)。
因此,答案如下:
- 为什么会发生这种异常
- 这与在当地阅读有关吗
- 重用ObjectMapper或其底层流时是否需要某种重置或其他操作
不需要。当使用与ObjectMapper类似的方法混合使用流API时,您需要注意的是,有时映射器/解析器可能会控制底层流。请参阅的Javadoc,并查看每个读取方法的文档,以满足您的需要。现在还有一个不错的新的
映射迭代器
可以通过ObjectReader
(由ObjectMapper
构造)获取,它允许您映射要迭代的值序列。它简化了操作,因此您无需使用JsonParser
,而只需使用类似于Mapping迭代器It=mapper.readerFor(JsonNode.class).readValues(src);