56

注: この問題も発生する場合は、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);

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 を完全に回避する必要がありますか?

4

3 に答える 3

63

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

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

10,000 回のテスト 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

//SomeNodeName90k 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

于 2011-06-14T09:45:02.743 に答える
6

解決策ではありませんが、主な問題へのポインタ:任意のノードに関連して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

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

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

于 2011-12-23T07:32:05.730 に答える