我正在使用 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 中读取的记录是“记录”元素中的元素。“...”表示那里有更多信息,符合我的记录。如果我只有一个分裂,那根本没有问题。我使用 JsonParser 进行细粒度(标题并移动到“记录”标记),然后我使用 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);
现在,假设我有一个包含两个输入分割的文件(即“记录”中有很多元素)。有效的 JSON 从第一次拆分开始,我读取并保留标题(每条记录都需要它,在本例中为“日期”字段)。
拆分将剪切 Records 数组中的任何位置。所以让我们假设我得到第二次这样的分裂:
...
},
{"TSSName":"ZZZ",
...
},
{"TSSName":"ZZZ2",
...
}
] } ] } } ]
我可以在开始解析之前进行检查,以将 InputStream (FSDataInputStream) 移动到记录的开头 ("{" ),其中包含下一个 "TSSNAME"(这可以完成)。在开始时丢弃尾随的“垃圾”很好。所以我们得到了这个:
{"TSSName":"ZZZ",
...
},
{"TSSName":"ZZZ2",
...
},
...
] } ] } } ]
然后我将它处理到上面看到的 JsonParser/ObjectMapper 对。第一个对象“ZZZ”读取正常。但是对于下一个“ZZZ2”,它打破了:JSONParser 抱怨 JSON 格式错误。它遇到一个“,”不在数组中。所以它失败了。然后我无法继续阅读我的记录。
如何解决这个问题,所以我仍然可以从第二个(和第 n 个)拆分中读取我的记录?如何让解析器忽略逗号上的这些错误,或者让解析器提前知道它正在读取数组的内容?