Ускорение XPath

У меня есть 1000 документов, чей формат что-то вроде

<Example>
     <Entry>
          <n1></n1>
          <n2></n2>
      </Entry>
      <Entry>
          <n1></n1>
          <n2></n2>
      </Entry>
      <!--and so on-->

Здесь более 1000 узлов входа. Я пишу Java-программу, которая в основном получает все узлы один за другим и проводит анализ каждого узла. Но проблема в том, что время поиска узлов увеличивается с его нет. Например, для извлечения первого узла требуется 78 миллисекунд, а для извлечения второго - 100 мс, и он продолжает увеличиваться. И для получения узла 999 требуется более 5 секунд. Это очень медленно. Мы будем подключать этот код к XML-файлам, которые имеют даже более 1000 записей. Некоторым нравятся миллионы. Общее время разбора всего документа составляет более 5 минут.

Я использую этот простой код, чтобы пройти его. Вот nxp мой собственный класс, который имеет все методы для получения узлов из xpath.

nxp.fromXpathToNode("/Example/Entry" + "[" + i  + "]", doc);    

а также doc это документ для файла. i это номер узла для извлечения.

Также, когда я пытаюсь что-то вроде этого

List<Node> nl = nxp.fromXpathToNodes("/Example/Entry",doc);  
      content = nl.get(i);    

Я сталкиваюсь с той же проблемой.

У любого есть какое-либо решение о том, как ускорить третичное сравнение узлов, поэтому для получения 1-го узла, а также 1000-го узла из файла XML требуется одинаковое количество времени.

Спасибо


Вот код для xpathtonode.

public Node fromXpathToNode(String expression, Node context)  
{  
    try  
    {  
        return (Node)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODE);  
    }  
    catch (Exception cause)  
    {  
        throw new RuntimeException(cause);  
    }  
}  

и вот код для xpathtonodes.

public List<Node> fromXpathToNodes(String expression, Node context)  
{  
    List<Node> nodes = new ArrayList<Node>();  
    NodeList results = null;  

    try  
    {  
        results = (NodeList)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODESET);  

        for (int index = 0; index < results.getLength(); index++)  
        {  
            nodes.add(results.item(index));  
        }  
    }  
    catch (Exception cause)  
    {  
        throw new RuntimeException(cause);  
    }  

    return nodes;  
}  

и вот старт

открытый класс NativeXpathEngine реализует XpathEngine
{
закрытый финальный завод XPathFactory;

private final XPath engine;  

/**
 * Cache for previously compiled XPath expressions. {@link XPathExpression#hashCode()}
 * is not reliable or consistent so use the textual representation instead.
 */  
private final Map<String, XPathExpression> cachedExpressions;  

public NativeXpathEngine()  
{
    super();  

    this.factory = XPathFactory.newInstance();  
    this.engine = factory.newXPath();  
    this.cachedExpressions = new HashMap<String, XPathExpression>();  
}  

6 ответов

Попробуйте VTD-XML. Он использует меньше памяти, чем DOM. Это проще в использовании, чем SAX и поддерживает XPath. Вот пример кода, который поможет вам начать работу. Он применяет XPath для получения элементов Entry, а затем распечатывает дочерние элементы n1 и n2.

final VTDGen vg = new VTDGen();
vg.parseFile("/path/to/file.xml", false);

final VTDNav vn = vg.getNav();
final AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/Example/Entry");
int count = 1;
while (ap.evalXPath() != -1) {
    System.out.println("Inside Entry: " + count);

    //move to n1 child
    vn.toElement(VTDNav.FIRST_CHILD, "n1");
    System.out.println("\tn1: " + vn.toNormalizedString(vn.getText()));

    //move to n2 child
    vn.toElement(VTDNav.NEXT_SIBLING, "n2");
    System.out.println("\tn2: " + vn.toNormalizedString(vn.getText()));

    //move back to parent
    vn.toElement(VTDNav.PARENT);
    count++;
}

Правильным решением является отсоединение узла сразу после вызова item(i), например, так:

Node node = results.item(index)
node.getParentNode().removeChild(node)
nodes.add(node)

См XPath.evaluate производительность замедляется (абсурдно) при нескольких вызовах

У меня была похожая проблема с оценкой Xpath, я пытался использовать CachedXPathAPI, который в 100 раз быстрее, чем XPathApi, который использовался ранее. дополнительная информация об этом API приведена здесь: http://xml.apache.org/xalan-j/apidocs/org/apache/xpath/CachedXPathAPI.html

Надеюсь, поможет. Ура, Мадхусудхан

Если вам нужно разобрать огромные, но плоские документы, SAX - хорошая альтернатива. Это позволяет вам обрабатывать XML как поток вместо создания огромного DOM. Ваш пример может быть проанализирован с помощью ContentHandler, как это:

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;

public class ExampleHandler extends DefaultHandler2 {

    private StringBuffer chars = new StringBuffer(1000);

    private MyEntry currentEntry;
    private MyEntryHandler myEntryHandler;

    ExampleHandler(MyEntryHandler myEntryHandler) {
        this.myEntryHandler = myEntryHandler;
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        chars.append(ch);
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        if ("Entry".equals(localName)) {
            myEntryHandler.handle(currentEntry);
            currentEntry = null;
        }
        else if ("n1".equals(localName)) {
            currentEntry.setN1(chars.toString());
        }
        else if ("n2".equals(localName)) {
            currentEntry.setN2(chars.toString());
        }
    }


    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        chars.setLength(0);
        if ("Entry".equals(localName)) {
            currentEntry = new MyEntry();
        }
    }
}

Если документ имеет более глубокую и сложную структуру, вам потребуется использовать стеки, чтобы отслеживать текущий путь в документе. Тогда вам следует подумать о написании ContentHandler общего назначения, чтобы выполнить грязную работу и использовать с зависимыми от типа документа обработчиками.

Какой парсер вы используете?

DOM извлекает весь документ из памяти - как только вы извлекаете весь документ из памяти, ваши операции могут быть быстрыми, но это может оказать влияние на веб-приложение или цикл for.

SAX-парсер выполняет синтаксический анализ по требованию и загружает узлы по мере необходимости.

Поэтому попробуйте использовать реализацию парсера, которая соответствует вашим потребностям.

Используйте библиотеку JAXEN для xpaths: http://jaxen.codehaus.org/

Другие вопросы по тегам