2017-11-24 8 views
0

ターゲット・システムが受け入れて処理するのをサポートするために、5 MBを超えるXMLドキュメントをより小さなチャンクに分割する必要があります。 XSLT v2ではサイズ別に分割されたXML文書がサポートされているように見えるので、Javaプログラムを作成することになりました。このプログラムは、文書が10 MB未満または10 MB未満の場合にうまく機能します。 32 MBのファイルが供給されると、プログラムは失敗します。プログラムはエージェントとして動作し、最大メモリーが25GBに設定されたJVMに接続されます。それにもかかわらず、我々は永続的にOOMヒープ空間エラーを見る。ヒープダンプファイルを生成することは、問題の容疑者1として、次のことを明らかに:これに基づきJava |サイズで分割されたXML | HashMapのパフォーマンスの問題| OOMヒープ・スペース・エラー

sun.misc.Launcher$AppClassLoader @ 0x1bb7ae098" occupies 156,512,240 (64.62%) bytes. The memory is accumulated in one instance of 

、私はプログラムを検査開始し、潜在的にメモリの問題を引き起こす可能性がスポットを推定し、それがある[あなたがSYSOUT年代のいくつか無視することがこれらは私のデバッグセッション]のために添加したとおり

public static HashMap < Integer, String > splitPromotionItem(List promotionsItems, int promotionItemMaxSizeUoMNumericValue, int promotionItemMaxSize, String routingLocation, String docNum, XDNode messageHeader, XDNode promotionsData){ 
    HashMap < Integer, String > promotionItemMap = new HashMap < Integer, String >(); 
    int totalSubMessage = 1; 
    String promotionsItemsData = ""; 
    int promotionsItemsSize = 0; 
    String promotionsItemsDataTemp = ""; 
    int i = 0; 
    int q = 1; 
    do { 
     promotionsItemsSize = promotionsItemsSize + ((XDNode) promotionsItems.get(i)).flatten().getBytes().length; 
     promotionsItemsData = promotionsItemsData + ((XDNode) promotionsItems.get(i)).flatten(); 

     if (promotionsItemsSize > (promotionItemMaxSize * 1024 * 1024)) { 
      System.out.println("Inside First If: " + promotionsItems.size() + ": " + q++); 
      promotionsItemsSize = promotionsItemsSize - ((XDNode) promotionsItems.get(i)).flatten().getBytes().length; 
      promotionsItemsData = promotionsItemsDataTemp; 
      promotionItemMap.put(totalSubMessage++, promotionsItemsData); 
      if (i != (promotionsItems.size() - 1)) { 
       System.out.println("Inside Second If: " + promotionsItems.size()); 
       i--; 
       promotionsItemsSize = 0; 
       promotionsItemsData = ""; 
      } else { 
       System.out.println("Inside Second Else: " + promotionsItems.size()); 
       promotionsItemsSize = ((XDNode) promotionsItems.get(i)).flatten().getBytes().length; 
       promotionsItemsData = ((XDNode) promotionsItems.get(i)).flatten(); 
      } 
     } 
     if (promotionsItemsSize < (promotionItemMaxSize * 1024 * 1024) && (i) == (promotionsItems.size() - 1)) { 
      promotionItemMap.put(totalSubMessage++, promotionsItemsData); 
     } 
     i++; 
     promotionsItemsDataTemp = promotionsItemsData; 
    } while (i < promotionsItems.size()); 

    return promotionItemMap; 
} 

プログラムは、まず、後の各エントリを介してその反復関数に供給されるハッシュマップに格納されている小さなチャンクに大きなXML文書を分割するように見えますマップしてファイルに書き込みます。ファイルの名前と内部の要素の1つは、分割バッチ内のファイルのインデックスと、簡単に認識できるように合計分割数を保持します。

最初の考えでは、コードを次のように改訂しました。小さなXMLチャンクをHashMapに集める代わりに、ファイルに直接書き込んでください。これはまた、すべての小さなチャンクがディスクに保存された後に、それらを再度開いて、ファイルインデックスとファイル総数とファイル名の内容を更新する必要があります。

これを処理する方法はありますか?助けてください。

注:JVMは毎日大量のデータを処理し、次の起動オプションを負い、私たちは、XSLTプロセサとしてサクソン使用:

-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl -Xmx15360M -Xrs -XX:GCTimeRatio=5 -XX:+PrintGCDetails -Xloggc:<location> -XX:MinHeapFreeRatio=25 -XX:MaxHeapFreeRatio=60 

アップデート29112017

クラスの使用XDNodeとその機能flattenは、プロセスフローをシームレスに実行するためにエージェントをJVMにプラグインできるように、iWayが提供するAPIでプログラムを拡張した結果です。

XDNodeは、XMLツリーの単一要素です。完全な文書はXDNodeのツリーです。 XDNodeクラスとツリーは、高速な解析と検索、およびアプリケーションでの簡単な操作のために設計されています。メソッドは、XDNodeツリーと標準JDOMツリーの間で変換するために利用できます。すべてのサーバー操作はXDNodeのツリーで実行されます。

flatten()は、XMLドキュメント全体をStringとして返します。

Sample XML Document

分割操作がエレメント/ SalonApps /プロモーション/ PromotionData/PromotionItemで実行されます。ここでは

は、XML文書は次のようになります方法の例です。 PromotionItemが発生するたびに反復処理を行い、上記のコードのように反復されたチャンクを一時変数に格納します。また、パッケージングとファイル書き込み操作を実行する必要性を判断するために、各反復の開始時に5 MB [クラスの冒頭で定義された制限]を超えるサイズがあるかどうかを確認します。サイズが小さくなると、反復はさらに収集されて保存されます。ドキュメントのヘッダーセクション[/ SalonApps/Promotion/MessageHeader]は、スプリットメッセージのインデックスをバッチで反映するように変更されたMessageIDの値と、2番目と3番目の場所でのバッチの合計カウントを使用して、各分割ドキュメントに追加されます値はハイフンで区切られます。

XSLT v1およびv2のみをサポートしています。 XSLT v1またはv2を使用してXML文書をそのサイズで分割することができれば、それは素晴らしいことです。

+0

XDNodeとは何ですか? XDNodeのflatten()操作は何をしますか? XML文書の構造は何ですか?どのようにそれを分割しようとしていますか?これらの質問に対する答えを知らなくても、私たちはあなたのコードを理解することができますか? –

+0

@MichaelKay、遅れのために私の謝罪。私は気分が悪かった。私はあなたに示された項目に対処するための明確さを加えました。ありがとうございました。 – Srii

答えて

1

問題の基本的な原因は、おそらくこれです:あなたはインクリメンタル文字列の連結により、ループ内で大規模な文字列を構築している

promotionsItemsData = 
    promotionsItemsData + ((XDNode) promotionsItems.get(i)).flatten(); 

。それはJavaでは非常に悪いニュースです。文字列をStringBuilderで構築する必要があります。

これはおそらく問題を解決するのに十分であるはずですが、私は個人的には全く別の方法で問題に取り組んでいます。私は、文書のツリービューに適用されるいくつかの基準に基づいてファイルを分割する場所を決定し、ノードをシリアル化してサイズを測定するのではなく、各出力部分に入れるノードを選択して通常の方法で直列化しますシリアライズされた部分。

+0

2番目の提案のサンプルコードスニペットがありますか?私はそれを見てみたいです... – Srii

2

あなたがしようとしていることを正確に理解することは非常に難しいですが、サンプルコードをリバースエンジニアリングすることによって洞察を得るのは確かに非常に困難です。しかし、あなたはXSLTソリューションに興味を示しているので、ここで提案します。

あなたの文書がフラットな形の構造、本質的である場合:

<table> 
    <record>...</record> 
    <record>...</record> 
    ... 
</table> 

とは、レコードの数は、文書のサイズのための合理的なプロキシがある場合、あなたは簡単に持っているそれぞれの断片に分割することができますNの最大サイズ(記録)(あなたが200MBの以上の取り扱いを開始するまで、ストリーミングは必要ありませんが)あなたがXSLT 3.0を使用する場合は、このソリューションがストリーミングであることにも注意

<xsl:template match="table"> 
    <xsl:for-each-group select="record" group-adjacent="(position()-1) idiv $N"> 
    <xsl:result-document href="part{position()}"> 
     <table> 
     <xsl:copy-of select="current-group()"/> 
     </table> 
    </xsl:result-document> 
    </xsl:for-each-group> 
</xsl:template> 

を使用。

これがあなたがやろうとしていることでない場合は、要件をより明確に説明する必要があります。

+0

xslt v3でストリーミング可能な可能性について素敵なヒント – Srii

関連する問題