如果是大型XML输入文件

时间:2015-09-15 16:17:59

标签: hadoop mapreduce

我有一个非常大的输入文件,它是一个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

3 个答案:

答案 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;