如何在大型xml输入文件的情况下处理hadoop拆分

bq9c1y66  于 2021-05-29  发布在  Hadoop
关注(0)|答案(3)|浏览(249)

我有一个非常大的输入文件,它是xml数据。
所以现在当我把它放到hdfs中时,逻辑上hdfs块将被创建,xml记录也将被划分到块中。现在,典型的textinputformat通过跳过第一行(如果它不是行的开始)来处理该场景,并且在逻辑上,上一个Map器从该块读取(通过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被破坏),但这是否也会解决最后一个Map器从下一个输入拆分中完成记录的问题?
请纠正我,如果有一些根本性的问题,如果有任何解决办法,这将是一个很大的帮助。
谢谢,aj

tzxcd3kk

tzxcd3kk1#

可能先拆分xml文件。有开源的xml拆分器。另外,至少有两个商业拆分工具声称可以自动处理xml结构,以确保每个拆分文件都是格式良好的xml。谷歌“xml拆分工具”或“xml拆分器”

nhaq1z21

nhaq1z212#

我不认为一个xml文件本身是可拆分的。那么我认为没有一个通用的公共解决方案。问题是,除非事先知道xml的结构,否则无法理解从xml中间开始的标记层次结构。
但是xml非常简单,可以创建一个临时拆分器。正如您所解释的,textinputformat跳过第一个字符,直到到达新文本行的开头。好吧,你可以做同样的事情寻找图书标签,而不是一个新的行。复制代码,但要查找“\n”字符,请查找项目的打开标记。
一定要在开发中使用sax解析器,使用dom不是处理大型xml的好选择。在sax解析器中,您逐个读取每个标记,并在每个事件中执行一个操作,而不是像生成dom树那样将所有文件加载到内存中。

dy2hfwbg

dy2hfwbg3#

您完全可以尝试mahout的xmlinputformat类。更多解释请参见《hadoop在行动》一书

相关问题