注:この問題も発生する場合は、Apache JIRAでそれを支持してください:
私はこれについて驚くべき結論に達しました:
_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を完全に避けるべきですか?
私はテストケースとXalan/JAXP全般をデバッグしてプロファイルを作成しました。私は大きな大きな問題を特定することができました
_org.Apache.xml.dtm.ObjectFactory.lookUpFactoryClassName()
_
10kテストのXPath評価のたびに、クラスローダーが何らかのデフォルト構成のDTMManager
インスタンスを検索しようとしたことがわかります。この構成はメモリにロードされず、毎回アクセスされます。さらに、このアクセスは_ObjectFactory.class
_自体のロックによって保護されているようです。アクセスが失敗すると(デフォルト)、構成は_xalan.jar
_ファイルの
_META-INF/service/org.Apache.xml.dtm.DTMManager
_
構成ファイル。 毎回!:
幸いなことに、この動作は、次のような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の人々に提出しました。
解決策ではなく、主な問題へのポインタ:任意のノードに関連してxpathを評価するプロセスのslowest部分は、 DTMマネージャーを使用してノードハンドルを見つけます。
問題のノードがドキュメントの最後にある場合、すべてのクエリについて、ツリー全体を検索して問題のノードを見つけることができます。
これは、ターゲットノードから孤立するハックが機能する理由を説明しています。これらのルックアップをキャッシュする方法はshouldがありますが、現時点ではその方法がわかりません。
あなたの質問に答えるために、vtd-xmlはJaxenやXalanよりもはるかに高速です(平均して10倍、60倍が報告されていると言います...