2

最大 1GB の XML ファイルがあります。OutOfMemory 例外を回避するために XOM を使用しています。

ドキュメント全体を正規化する必要がありますが、1.5 MB のファイルでも正規化に時間がかかります。

これが私がやったことです:

このサンプル XML ファイルがあり、Item ノードを複製してドキュメントのサイズを増やします。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Packet id="some" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Head>
<PacketId>a34567890</PacketId>
<PacketHeadItem1>12345</PacketHeadItem1>
<PacketHeadItem2>1</PacketHeadItem2>
<PacketHeadItem3>18</PacketHeadItem3>
<PacketHeadItem4/>
<PacketHeadItem5>12082011111408</PacketHeadItem5>
<PacketHeadItem6>1</PacketHeadItem6>
</Head>
<List id="list">
    <Item>
        <Item1>item1</Item1>
        <Item2>item2</Item2>
        <Item3>item3</Item3>
        <Item4>item4</Item4>
        <Item5>item5</Item5>
        <Item6>item6</Item6>
        <Item7>item7</Item7>
    </Item>
</List>
</Packet>

正規化に使用しているコードは次のとおりです。

private static void canonXOM() throws Exception {
    String file = "D:\\PACKET.xml";
    FileInputStream xmlFile = new FileInputStream(file);

    Builder builder = new Builder(false);
    Document doc = builder.build(xmlFile);

    FileOutputStream fos = new FileOutputStream("D:\\canon.xml");
    Canonicalizer outputter = new Canonicalizer(fos);

    System.out.println("Query");
    Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");

    System.out.println("Canon");
    outputter.write(nodes);

    fos.close();
}

このコードは小さなファイルにはうまく機能しますが、私の開発環境 (4 GB RAM、64 ビット、Eclipse、Windows) では、1.5 MB のファイルの正規化部分に約 7 分かかります。

この遅延の原因へのポインタは高く評価されます。

PS。XML ドキュメント全体からのセグメントと、ドキュメント全体を正規化する必要があります。したがって、ドキュメント自体を引数として使用してもうまくいきません。

一番

4

3 に答える 3

1

メモリは制限ではありません

memory is not restriction

メインスレッドは緑でブロックされていません

main thread is green and no blocking. it is using as much cpu as it can. 
because my machine has multi-cores , so the CPU total usage is not full.
But it will be full for a single CPU the main thread is running on.

Nodes.contains は最も忙しいものです

Nodes.contains is the most busy one

内部ではノードをリストで管理し、直線的に比較していました。リスト内のアイテムが増えると、「contains」が遅くなります。

private final List nodes;
public boolean contains(Node node) {
    return nodes.contains(node);
}

それで

  • HashMap を使用してノードを保持するように lib のコードを変更してみてください。
  • または、XML を小さな xml に分割できる場合は、マルチスレッドを使用してより多くの CPU を使用します。

ツール: JVisualVM. http://docs.oracle.com/javase/6/docs/technotes/guides/visualvm/index.html

于 2012-12-05T10:37:49.300 に答える
0

あなたがXOMをあきらめても構わないと思っているなら、私はあなたの問題に対する解決策を持っているかもしれません。私のソリューションは、XPathAPIとApacheSantuarioを使用することで構成されます

性能の違いは印象的ですが、比較してみるといいと思いました。

テストでは、質問で提供した1.5MBのXMLファイルを使用しました。

XOMテスト

FileInputStream xmlFile = new FileInputStream("input.xml");

Builder builder = new Builder(false);
Document doc = builder.build(xmlFile);

FileOutputStream fos = new FileOutputStream("output.xml");
nu.xom.canonical.Canonicalizer outputter = new nu.xom.canonical.Canonicalizer(fos);

Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");
outputter.write(nodes);

fos.close();

XPath/Santuarioテスト

org.apache.xml.security.Init.init();

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
org.w3c.dom.Document doc = builder.parse("input.xml");

XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();

org.w3c.dom.NodeList result = (org.w3c.dom.NodeList) xpath.evaluate("./descendant-or-self::node()|./@*", doc, XPathConstants.NODESET);

Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
byte canonXmlBytes[] = canon.canonicalizeXPathNodeSet(result);

IOUtils.write(canonXmlBytes, new FileOutputStream(new File("output.xml")));

結果

グラフィック結果

以下は、秒単位の結果の表です。テストは16回実行されました。

╔═════════════════╦═════════╦═══════════╗
║      Test       ║ Average ║ Std. Dev. ║
╠═════════════════╬═════════╬═══════════╣
║ XOM             ║ 140.433 ║   4.851   ║
╠═════════════════╬═════════╬═══════════╣
║ XPath/Santuario ║ 2.4585  ║  0.11187  ║
╚═════════════════╩═════════╩═══════════╝

パフォーマンスの違いは非常に大きく、XMLパス言語の実装に関連しています。XPath / Santuarioを使用することの欠点は、XOMほど単純ではないことです。

テストの詳細

マシン:Intel Core i5 4GB RAM
SO:Debian 6.0 64ビット
Java:OpenJDK 1.6.0_18 64ビットXOM
:1.2.8
Apache Santuario:1.5.3

于 2012-12-06T14:12:11.190 に答える
0

ドキュメント全体をシリアライズしたいので、置き換えていただけますか

Nodes nodes = doc.getRootElement().query("./descendant-or-self::node()|./@*");
outputter.write(nodes);

outputter.write(doc);

?

Canonicalizer正規化するルートノードだけでなく、ノードリストを指定すると、追加の作業 ( nodes.contains()whunmr で言及されている呼び出しなど)を行うように見えます。

それがうまくいかない、または十分でない場合はCanonicalizer、プロファイリングで提案されているように、そこでフォークして最適化を行います。

于 2012-12-05T13:58:34.360 に答える