2

Nokogiri/Ruby を使用して非常に大きな XML ドキュメント (~300k 行) を解析しています。各レコードの処理に約 5 分かかりましたが、以下のコードの最後の行がその時間の 99% を占めていることがわかりました。検索を高速化する方法について何か提案はありますか? ひょっとして、システム メモリ (またはその不足) に問題がある可能性はありますか?

doc = Nokogiri::XML(File.read(ARGV[0]))
orders = doc.xpath("//order")

order = orders.xpath("//order[account_number=#{sap_account}]")
4

2 に答える 2

3

簡単な修正

の代わりにルートからのフル パスを使用して、単一の XPath を試してください//

例:

order = doc.at("/full/path/to/order[account_number=#{sap_account}]")

//ドキュメント全体をスキャンするため、パフォーマンスを向上させるために最初に取り除く必要があります。

本当に高速化したい場合は、SAX または Reader インターフェースを使用してください。

本当の速さ: Reader インターフェース

Reader インターフェース (および SAX) は、文書全体を DOM に構文解析する必要がないため、高速になります。一度に 1 つのノードでドキュメントを直線的に通過するだけです。これにより、利便性を犠牲にして速度が向上します (クエリやバックトラッキングはありません)。代わりに、必要な条件について各ノードをテストする必要があります。

Reader インターフェースを使用した例を次に示します (これは SAX よりも少し単純です)。次のファイルがあるとします。

<orders>
  <order account_number="1">
    <item>Foo</item>
  </order>
  <order account_number="2">
    <item>Bar</item>
  </order>
  <order account_number="3">
    <item>Baz</item>
  </order>
</orders>

<item>のの順に をaccount_number取り出したいとしましょう2。コードは次のとおりです。

require 'nokogiri'
filename = ARGV[0]
sap_account = "2"

File.open(filename) do |file|
  Nokogiri::XML::Reader.from_io(file).each do |node|
    if node.name == 'order' and node.attribute('account_number') == sap_account
      puts node.inner_xml
    end
  end
end

出力:

<item>Bar</item>
于 2013-11-08T01:52:43.453 に答える
1

1 つまたは複数のノードの検索をステップに分割すると便利なことがよくありますが、これを 1 つのステップで実行できるように見えます。

doc = Nokogiri::XML(File.read(ARGV[0]))
order = doc.xpath("//order[account_number=#{sap_account}]")

そのノードのオカレンスが 1 つしかない場合は、次を使用します。

order = doc.at("//order[account_number=#{sap_account}]")

違いはxpath、ノードのコレクションである NodeSet を返すことです。NodeSet は同じメソッドの多くをサポートしますが、単一のノードではなく配列のような構造に適用されるため、微妙な違いが生じる可能性があります。at最初に一致したノードを返すため、返されたノードに対して行う以降の処理は、そのノードにのみ適用され、他のノードには適用されません。

xpathの XPath 固有バージョンであり、 CSS セレクターsearchのマッチング メソッドを備えています。CSS セレクターと XPath セレクターの両方を受け入れ、その場でどちらを使用するかを決定します。同様に、それぞれと の CSS と XPath の帰結があります。私は、XPath が CSS と間違えられて Nokogiri がびっくりするような場合にのみ、CSS と XPath のバリアントを使用する傾向があります。csssearchatat_cssat_xpathsearchat

Nokogiri は//order[account_number=#{sap_account}]、十分なメモリがあれば、300K 行であっても、非常に高速に検索して見つける必要があります。

そうでない場合は、XML をデータベースにインポートすることを真剣に検討し、そこで検索を行ってください。XML は実際にはデータストアとして使用することを意図したものではないため、XML ファイルに対する処理は流れに逆らって作業を困難にする可能性があります。スキーマを作成し、インデックス付きフィールドを使用してデータベースにインポートすると、処理が大幅に高速化されます。

于 2013-11-08T02:41:42.957 に答える