【问题标题】:How to improve performance of querying xml file with VTD-XML and XPath?如何提高使用 VTD-XML 和 XPath 查询 xml 文件的性能?
【发布时间】:2019-04-15 14:01:58
【问题描述】:

我正在查询大小约为 1 MB(20k+ 行)的 XML 文件。我正在使用 XPath 来描述我想要获取的内容,并使用 VTD-XML 库来获取它。我认为我在性能方面存在一些问题。

问题是,我正在对 XML 文件进行大约 5k+ 次查询。检索所有值大约需要 16-17 秒。我想问你,这是否是此类任务的正常表现?我该如何改进它?

我正在使用带有 AutoPilot 导航方法的 VTD-XML 库,这让我有机会使用 XPath。实现如下:

private VTDGen vg = new VTDGen();
private VTDNav vn;
private AutoPilot ap = new AutoPilot();

public void init(String xml) {
    log.info("Creating document");
    xml = xml.replace("<?xml version=\"1.0\"?>", "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    byte[] bytes = xml.getBytes(StandardCharsets.UTF_8);
    vg.setDoc(bytes);
    try {
        vg.parse(true);
        vn = vg.getNav();
    } catch (ParseException e) {
        e.printStackTrace();
    }
    log.info("Document created");
}

public String parseXmlOrReturnNull(String query) {
    String xPathStringVal = null;
    try {
        ap.selectXPath(query);
        ap.bind(vn);
        int i = -1;
        while ((i = ap.evalXPath()) != -1) {
            xPathStringVal = vn.getXPathStringVal();
        }
    }catch (XPathEvalException e) {
        e.printStackTrace();
    } catch (NavException e) {
        e.printStackTrace();
    } catch (XPathParseException e) {
        e.printStackTrace();
    }
    return xPathStringVal;
}

我的 xml 文件有特定的格式,它们被分成很多部分 - 段,我的查询对于所有段都是相同的(我在循环中查询它)。例如部分xml:

<segment>
    <a>
        <b>value1</b>
        <c>
            <d>value2</d>
            <e>value3</d>
        </c>
    </a>
</segment>
<segment>
    <a>
        <b>value4</b>
        <c>
            <d>value5</d>
            <e>value6</d>
            <f>value6</d>
        </c>
    </a>
</segment>
...

如果我想在第一段中获取 value1,我正在使用查询:

//segment[1]/a/b

第二段中的值 4

//segment[2]/a/b

等等

直觉说明了几点:在我的方法中,每个查询都是独立的(它对其他查询一无所知),这意味着我的迭代器 AutoPilot 总是在我想查询文件的开头开始.

我的问题是:有没有办法在处理段开始时设置 AutoPilot?当我完成查询时将 AutoPilot 移动到下一段?我认为如果我的方法不是从头开始搜索值,而是从指定点开始搜索会快得多。

另一种方法是将xml文件分成小的xml文件(一个xml文件=一个段)并查询那些小的xml文件。

你们觉得呢?提前致谢

【问题讨论】:

  • 任何以//x 开头的模式都非常昂贵,这意味着“在任何深度检查名为 x 的节点”,这基本上会迫使您的处理器获取每个节点来查看它们。如果您知道您对哪些segments 感兴趣,请限定您的路径,例如/segment[1]/whatever/segment[1] 会快很多。第二:如果你的 XPath 查询事先知道,预编译它们(我对 VTD XML 了解不够,但它是大多数 XPath 引擎的标准功能)。

标签: java xml vtd-xml


【解决方案1】:

次要:不需要替换,因为 UTF-8 是默认编码;仅当存在 编码时,才需要将其修补为 UTF-8。

XPath 应该只执行一次,而不是从 [0] 开始到下一个索引。

如果您需要一个列表表示,您可以使用带有注释的 JAXB。

基于事件的原始解析没有 DOM 对象可能是最好的(SAXParser)。

Handler handler = new org.xml.sax.helpers.DefaultHandler {
    @Override
    public void startElement(String uri, 
        String localName, String qName, Attributes attributes) throws SAXException {
    }

    @Override
    public void endElement(String uri, 
        String localName, String qName) throws SAXException {
    }

    @Override
    public void characters(char ch[], int start, int length) throws SAXException {
    }
};
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
InputStream in = new ByteArrayInputStream(bytes);
parser.parse(in, handler);

【讨论】:

    猜你喜欢
    • 2019-10-30
    • 2017-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多