我有一个非常大的输入文件,它是一个XML数据。
所以现在当我把它放在HDFS中时,逻辑上将创建HDFS块,并且XML记录也将在块之间分配。现在,典型的TextInputFormat通过跳过第一行来处理场景,如果它不是行的开头,并且逻辑上前一个映射器从该块读取(通过RPC)直到记录结束。
在XML案例中我们如何处理这种情况?我不想使用WholeFileInputFormat,因为这不会帮助我使用并行性。
<books>
<book>
<author>Test</author>
<title>Hadoop Recipes</title>
<ISBN>04567GHFR</ISBN>
</book>
<book>
<author>Test</author>
<title>Hadoop Data</title>
<ISBN>04567ABCD</ISBN>
</book>
<book>
<author>Test1</author>
<title>C++</title>
<ISBN>FTYU9876</ISBN>
</book>
<book>
<author>Test1</author>
<title>Baby Tips</title>
<ISBN>ANBMKO09</ISBN>
</book>
</books>
XMLRecordReader的初始化函数类似于 -
public void initialize(InputSplit arg0, TaskAttemptContext arg1)
throws IOException, InterruptedException {
Configuration conf = arg1.getConfiguration();
FileSplit split = (FileSplit) arg0;
start = split.getStart();
end = start + split.getLength();
final Path file = split.getPath();
FileSystem fs = file.getFileSystem(conf);
fsin = fs.open(file);
fsin.seek(start);
DocumentBuilder db = null;
try {
db = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Document doc = null;
try {
doc = db.parse(fsin);
} catch (SAXException e) {
e.printStackTrace();
}
NodeList nodes = doc.getElementsByTagName("book");
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
BookWritable book = new BookWritable();
NodeList author = element.getElementsByTagName("author");
Element line = (Element) author.item(0);
book.setBookAuthor(new Text(getCharacterDataFromElement(line)));
NodeList title = element.getElementsByTagName("title");
line = (Element) title.item(0);
book.setBookTitle(new Text(getCharacterDataFromElement(line)));
NodeList isbn = element.getElementsByTagName("ISBN");
line = (Element) isbn.item(0);
book.setBookISBN(new Text(getCharacterDataFromElement(line)));
mapBooks.put(Long.valueOf(i), book);
}
this.startPos = 0;
endPos = mapBooks.size();
}
使用DOM解析器来处理XML解析部分,不确定但是如果我进行模式匹配则会解析DOM解析器解析问题(如果其中一个拆分中的XML损坏),那么解决最后一个映射器从下一个输入拆分中完成记录?
如果存在一些基本问题,请纠正我,如果有任何解决方案,那将是一个很大的帮助。
谢谢, AJ
答案 0 :(得分:0)
你可以尝试mahout的XMLinputFormat课程。 “Hadoop in action”一书中的更多解释
答案 1 :(得分:0)
我认为XML文件本身不能拆分。我认为没有适合您的通用公共解决方案。问题是除非你先验地知道XML的结构,否则无法理解从XML中间开始的标记层次结构。
但您的XML非常简单,您可以创建Ad-Hoc分割器。如您所述,TextInputFormat跳过第一个字符,直到它到达新文本行的开头。好吧,你可以做同样的事情寻找 book 标签而不是换行。复制代码,而不是寻找“\ n”字符查找商品的开放标记。
确保在开发中使用SAX解析器,使用DOM不是处理大XML的好选择。在SAX解析器中,您逐个读取每个标记并在每个事件中执行操作,而不是像生成DOM树一样在内存中加载所有文件。
答案 2 :(得分:0)
可能首先拆分XML文件。有开源XML分割器。还有至少两个声称自动处理XML结构的商业拆分工具,以确保每个拆分文件都是格式良好的XML。 Google&#34; xml拆分工具&#34;或&#34; xml拆分器&#34;