Производительность Java XPath (реализация Apache JAXP) - PullRequest
53 голосов
/ 14 июня 2011

ПРИМЕЧАНИЕ. Если вы столкнулись с этой проблемой, сообщите об этом в Apache JIRA:

https://issues.apache.org/jira/browse/XALANJ-2540

Я пришелк удивительному выводу, что это:

Element e = (Element) document.getElementsByTagName("SomeElementName").item(0);
String result = ((Element) e).getTextContent();

Кажется, невероятно в 100 раз быстрее, чем это:

// Accounts for 30%, can be cached
XPathFactory factory = XPathFactory.newInstance();

// Negligible
XPath xpath = factory.newXPath();

// Negligible
XPathExpression expression = xpath.compile("//SomeElementName");

// Accounts for 70%
String result = (String) expression.evaluate(document, XPathConstants.STRING);

Я использую реализацию JAXP по умолчанию в JVM:

org.apache.xpath.jaxp.XPathFactoryImpl
org.apache.xpath.jaxp.XPathImpl

Я действительно сбит с толку, потому что легко понять, как JAXP может оптимизировать вышеупомянутый запрос XPath, чтобы вместо этого фактически выполнить простой getElementsByTagName().Но, похоже, этого не происходит.Эта проблема ограничена 5-6 часто используемыми вызовами XPath, которые абстрагируются и скрываются API.Эти запросы включают простые пути (например, /a/b/c, без переменных, условий) только для всегда доступного документа DOM.Итак, если можно провести оптимизацию, ее будет довольно легко достичь.

Мой вопрос: является медлительностью XPath общепризнанным фактом или я что-то упускаю?Есть ли лучшая (более быстрая) реализация?Или мне просто следует избегать XPath для простых запросов?

Ответы [ 3 ]

60 голосов
/ 14 июня 2011

Я отладил и профилировал мой тестовый пример и Xalan / JAXP в целом. Мне удалось определить большую серьезную проблему в

org.apache.xml.dtm.ObjectFactory.lookUpFactoryClassName()

Видно, что каждый из тестов XPath с тестом 10k приводил к тому, что загрузчик классов пытался найти экземпляр DTMManager в какой-то конфигурации по умолчанию. Эта конфигурация не загружается в память, а доступна каждый раз. Кроме того, этот доступ, кажется, защищен блокировкой самого ObjectFactory.class. При сбое доступа (по умолчанию) конфигурация загружается из xalan.jar файла

META-INF/service/org.apache.xml.dtm.DTMManager

файл конфигурации. Каждый раз! :

JProfiler profiling results

К счастью, это поведение можно изменить, указав параметр JVM следующим образом:

-Dorg.apache.xml.dtm.DTMManager=
  org.apache.xml.dtm.ref.DTMManagerDefault

или

-Dcom.sun.org.apache.xml.internal.dtm.DTMManager=
  com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault

Сказанное выше работает, так как это позволит обойти дорогостоящую работу в lookUpFactoryClassName(), если имя класса фабрики все равно является значением по умолчанию:

// Code from com.sun.org.apache.xml.internal.dtm.ObjectFactory
static String lookUpFactoryClassName(String factoryId,
                                     String propertiesFilename,
                                     String fallbackClassName) {
  SecuritySupport ss = SecuritySupport.getInstance();

  try {
    String systemProp = ss.getSystemProperty(factoryId);
    if (systemProp != null) { 

      // Return early from the method
      return systemProp;
    }
  } catch (SecurityException se) {
  }

  // [...] "Heavy" operations later

Итак, вот обзор улучшения производительности для 10k последовательных оценок XPath //SomeNodeName против XML-файла 90k (измеряется с помощью System.nanoTime():

measured library        : Xalan 2.7.0 | Xalan 2.7.1 | Saxon-HE 9.3 | jaxen 1.1.3
--------------------------------------------------------------------------------
without optimisation    :     10400ms |      4717ms |              |     25500ms
reusing XPathFactory    :      5995ms |      2829ms |              |
reusing XPath           :      5900ms |      2890ms |              |
reusing XPathExpression :      5800ms |      2915ms |      16000ms |     25000ms
adding the JVM param    :      1163ms |       761ms |        n/a   |

обратите внимание, что тест был очень примитивным. вполне возможно, что ваш собственный тест покажет, что саксон превосходит xalan

Я подал это как ошибку для парней из Халана в Apache:

https://issues.apache.org/jira/browse/XALANJ-2540

6 голосов
/ 23 декабря 2011

Не решение, а указатель на главную проблему: самая медленная часть процесса оценки xpath относительно произвольного узла - это время, которое требуется менеджеру DTM для поиска дескриптора узла.:

http://javasourcecode.org/html/open-source/jdk/jdk-6u23/com/sun/org/apache/xml/internal/dtm/ref/dom2dtm/DOM2DTM.html#getHandleOfNode%28org.w3c.dom.Node%29

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

Это объясняет, почему работает взлом для потери целевого узла. должен быть способом кеширования этих поисков, но на данный момент я не могу понять, как.

0 голосов
/ 29 июля 2013

Чтобы ответить на ваш вопрос, vtd-xml работает намного быстрее, чем Jaxen или Xalan) (я бы сказал, в среднем 10x, а 60x сообщалось ...

...