[英]Extremely slow xpath search (ruby/nokogiri)
我正在使用Nokogiri / Ruby來解析非常大的XML文檔(約30萬行)。 處理每條記錄大約需要五分鍾,我確定下面代碼中的最后一行占用了該時間的99%。 關於如何加快搜索的任何建議? 可能是系統內存出現問題(或內存不足)嗎?
doc = Nokogiri::XML(File.read(ARGV[0]))
orders = doc.xpath("//order")
order = orders.xpath("//order[account_number=#{sap_account}]")
使用從root而不是//
的完整路徑嘗試一個XPath。
例:
order = doc.at("/full/path/to/order[account_number=#{sap_account}]")
//
掃描整個文檔,因此這是在嘗試提高性能時要擺脫的第一件事。
如果您確實想加快速度,請使用SAX或Reader接口。
Reader接口(以及SAX)將更快,因為它不必將整個文檔解析為DOM。 它只會一次線性地在文檔中一次通過一個節點。 這使您在犧牲便利性的前提下獲得了速度(無需查詢和回溯)。 相反,您必須測試每個節點的條件。
這是一個使用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>
假設您account_number
為2
的順序拉出<item>
。 這是代碼:
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>
雖然將一個或多個節點的搜索分為多個步驟通常很有用,但實際上看起來您可以一次完成此操作:
doc = Nokogiri::XML(File.read(ARGV[0]))
order = doc.xpath("//order[account_number=#{sap_account}]")
如果該節點只能出現一次,請使用:
order = doc.at("//order[account_number=#{sap_account}]")
區別在於xpath
返回一個NodeSet,它是Node的集合。 NodeSet支持許多相同的方法,但是它們會導致細微的差異,因為它們被應用於類似數組的結構而不是單個節點。 at
返回第一個匹配的節點,因此您對返回的Node進行的任何進一步處理將僅應用於該節點,而不會進行其他任何處理。
xpath
是特定於XPath的search
版本,具有與CSS選擇器匹配的css
方法。 search
接受CSS和XPath選擇器,並確定要動態使用的選擇器。 同樣, at
具有at_css
和at_xpath
CSS和XPath推論。 當我將XPath誤認為CSS導致Nokogiri瘋狂時,我傾向於使用search
和at
並且僅使用CSS和XPath變體。
Nokogiri應該非常快速地搜索並找到//order[account_number=#{sap_account}]
,即使它有足夠的內存可以使用,即使在300K行中也是如此。
如果不是,那么請認真考慮將XML導入數據庫並在其中進行搜索。 XML並不是真的要用作數據存儲,因此對XML文件進行處理可能會違反流程,使您的生活更加艱難。 創建架構並將其導入具有索引字段的數據庫中,可以大大加快處理速度。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.