programing

Java XPath (Apache JAXP 구현) 성능

procenter 2021. 1. 15. 19:44
반응형

Java XPath (Apache JAXP 구현) 성능


참고 :이 문제도 경험하는 경우 Apache JIRA에서 upvote하십시오 :

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);

JVM의 기본 JAXP 구현을 사용하고 있습니다.

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

JAXP가 위의 XPath 쿼리를 어떻게 최적화하여 실제로 간단한 getElementsByTagName()대신 실행할 수 있는지 쉽게 알 수 있기 때문에 정말 혼란 스럽습니다 . 그러나 그것은 그렇게하지 않는 것 같습니다. 이 문제는 API에 의해 추상화되고 숨겨진 약 5 ~ 6 개의 자주 사용되는 XPath 호출로 제한됩니다. 이러한 쿼리에는 /a/b/c항상 사용 가능한 DOM 문서에 대한 간단한 경로 (예 : 변수 없음, 조건)가 포함됩니다. 따라서 최적화를 수행 할 수 있다면 달성하기가 매우 쉽습니다.

내 질문 : XPath의 느린 속도가 허용되는 사실입니까, 아니면 무언가를 간과하고 있습니까? 더 나은 (빠른) 구현이 있습니까? 아니면 단순한 쿼리를 위해 XPath를 아예 피해야합니까?


일반적으로 테스트 케이스와 Xalan / JAXP를 디버깅하고 프로파일 링했습니다. 나는 큰 문제를 파악할 수 있었다.

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

10k 테스트 XPath 평가의 모든 DTMManager것이 일종의 기본 구성에서 인스턴스 를 조회하려고하는 클래스 로더를 유발했음을 알 수 있습니다 . 이 구성은 메모리에로드되지 않고 매번 액세스됩니다. 또한이 액세스는 ObjectFactory.class자체 잠금으로 보호되는 것 같습니다 . 액세스가 실패하면 (기본적으로) xalan.jar파일의 구성이로드됩니다.

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

구성 파일. 매번! :

JProfiler 프로파일 링 결과

다행히 다음과 같은 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

따라서 다음 //SomeNodeName은 90k XML 파일에 대한 10k 연속 XPath 평가에 대한 성능 개선 개요입니다 (다음으로 측정) 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   |

벤치 마크는 매우 원시적이었습니다. 자신의 벤치 마크가 saxon이 xalan을 능가한다는 것을 보여줄 수 있습니다.

나는 이것을 Apache의 Xalan 사람들에게 버그로 제출했습니다.

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


해결책은 아니지만 주요 문제에 대한 포인터 : 임의의 노드와 관련하여 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. 노드 % 29

문제의 노드가 문서의 끝에 있으면 각 쿼리에 대해 전체 트리를 걸어 문제의 노드를 찾을 수 있습니다.

이것은 대상 노드를 분리하는 해킹이 작동하는 이유를 설명합니다. 이러한 조회를 캐시하는 방법 있어야 하지만이 시점에서 방법을 볼 수 없습니다.


귀하의 질문에 답하기 위해 vtd-xml은 Jaxen 또는 Xalan보다 훨씬 빠릅니다) (평균 10x라고 말하고 60x 가보고되었습니다 ...

참조 URL : https://stackoverflow.com/questions/6340802/java-xpath-apache-jaxp-implementation-performance

반응형