web-dev-qa-db-ja.com

Java XPath(Apache JAXP実装)パフォーマンス

注:この問題も発生する場合は、Apache JIRAでそれを支持してください:

https://issues.Apache.org/jira/browse/XALANJ-254

私はこれについて驚くべき結論に達しました:

_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()を実際に実行する方法が簡単にわかるので、私は本当に混乱しています。しかし、それはそうではないようです。この問題は、APIによって抽象化されて隠されている、頻繁に使用される5〜6個のXPath呼び出しに限定されています。これらのクエリには、常に使用可能なDOMドキュメントのみに対する単純なパス(_/a/b/c_、変数、条件なし)が含まれます。したがって、最適化を実行できれば、非常に簡単に実現できます。

私の質問:XPathの遅さは受け入れられている事実ですか、それとも何かを見落としていますか?より良い(より速い)実装はありますか?または、単純なクエリのために、XPathを完全に避けるべきですか?

53
Lukas Eder

私はテストケースとXalan/JAXP全般をデバッグしてプロファイルを作成しました。私は大きな大きな問題を特定することができました

_org.Apache.xml.dtm.ObjectFactory.lookUpFactoryClassName()
_

10kテストのXPath評価のたびに、クラスローダーが何らかのデフォルト構成の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
_

したがって、90k XMLファイル(System.nanoTime()で測定)に対する_//SomeNodeName_の10k連続XPath評価のパフォーマンス改善の概要を次に示します。

_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のXalanの人々に提出しました。

https://issues.Apache.org/jira/browse/XALANJ-254

60
Lukas Eder

解決策ではなく、主な問題へのポインタ:任意のノードに関連してxpathを評価するプロセスのslowest部分は、 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

問題のノードがドキュメントの最後にある場合、すべてのクエリについて、ツリー全体を検索して問題のノードを見つけることができます。

これは、ターゲットノードから孤立するハックが機能する理由を説明しています。これらのルックアップをキャッシュする方法はshouldがありますが、現時点ではその方法がわかりません。

6
Robbie Matthews

あなたの質問に答えるために、vtd-xmlはJaxenやXalanよりもはるかに高速です(平均して10倍、60倍が報告されていると言います...

0
vtd-xml-author