我使用jackson来处理hadoop中成片出现的json。这意味着,它们是大文件,被切成块(在我的问题中,它是128m,但其实并不重要)。出于效率考虑,我需要它是流式的(不可能在内存中构建整个树)。
我混合使用jsonparser和objectmapper来读取输入。目前,我使用的是一种不可拆分的自定义inputformat,因此我可以读取整个json。
(有效)json的结构类似于:
[ { "Rep":
{
"date":"2013-07-26 00:00:00",
"TBook":
[
{
"TBookC":"ABCD",
"Records":
[
{"TSSName":"AAA",
...
},
{"TSSName":"AAB",
...
},
{"TSSName":"ZZZ",
...
}
] } ] } } ]
我想在recordreader中读取的记录是“records”元素中的元素。“…”意味着那里有更多的信息,这符合我的记录。如果我有一个唯一的分裂,没有任何问题。我使用jsonparser进行细粒度处理(头并移到“records”标记),然后使用objectmapper和jsonparser将记录作为对象读取。详情:
configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false);
MappingJsonFactory factory = new MappingJsonFactory();
mapper = new ObjectMapper(factory);
mapper.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES,false);
mapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS,false);
parser = factory.createJsonParser(iStream);
mapper.readValue(parser, JsonNode.class);
现在,假设我有一个包含两个inputspilt的文件(即“records”中有很多元素)。有效的json从第一个split开始,我读取并保留标题(每个记录都需要这些标题,在本例中是“date”字段)。
拆分将剪切记录数组中的任何位置。假设我得到第二次分裂,像这样:
...
},
{"TSSName":"ZZZ",
...
},
{"TSSName":"ZZZ2",
...
}
] } ] } } ]
在开始解析之前,我可以检查是否将inputstream(fsdatainputstream)移动到记录的开头(“{”),其中包含下一个“tssname”(这样做是正确的)。在开始时丢弃后面的“垃圾”是可以的。所以我们得到了这个:
{"TSSName":"ZZZ",
...
},
{"TSSName":"ZZZ2",
...
},
...
] } ] } } ]
然后我将其处理到上面看到的jsonparser/objectmapper对。第一个对象“zzz”读取正常。但是对于下一个“zzz2”,它打破了:jsonparser抱怨json格式错误。它遇到了一个“,”不在数组中。所以它失败了。然后我就不能继续看我的记录了。
如何解决这个问题,使我仍然可以阅读我的记录,从第二次(和第n次)分裂?如何让解析器忽略逗号上的这些错误,或者让解析器提前知道它正在读取数组的内容?
1条答案
按热度按时间7fhtutme1#
似乎只要捕捉到异常就可以了:解析器继续运行,并且能够通过objectmapper继续读取对象。
我真的不喜欢它-我想要一个解析器不能在非标准甚至坏的json上抛出异常的选项。所以我不知道这是否完全回答了这个问题,但我希望它能有所帮助。