2012-02-08 32 views
5

我有1.6GB的xml文件,當我使用SAX解析機它,它似乎並不爲串流或進食以塊的文件 - 而是出現要將整個文件加載到內存中(或者可能存在內存泄漏?),因爲我的紅寶石進程爬上了2.5gb的內存。我不知道它會停止增長,因爲我內存不足。解析與SaxMachine大文件似乎整個文件被加載到內存中

在一個更小的文件(50MB),它似乎也加載整個文件。我的任務遍歷xml文件中的記錄並將每條記錄保存到數據庫中。大約需要30秒的「怠速」,然後數據庫查詢突然開始執行。

我認爲SAX是應該讓你與這樣的大文件而不用在內存中加載了整個事情。

有什麼我可以忽略的嗎?

非常感謝

更新添加代碼示例

class FeedImporter 

    class FeedListing 
    include ::SAXMachine 

    element :id 
    element :title 
    element :description 
    element :url 

    def to_hash 
     {}.tap do |hash| 
     self.class.column_names.each do |key| 
      hash[key] = send(key) 
     end 
     end 
    end 
    end 

    class Feed 
    include ::SAXMachine 
    elements :listing, :as => :listings, :class => FeedListing 
    end 

    def perform 
    open('~/feeds/large_feed.xml') do |file| 

     # I think that SAXMachine is trying to load All of the listing elements into this one ruby object. 
     puts 'Parsing' 
     feed = Feed.parse(file) 

     # We are now iterating over each of the listing elements, but they have been "parsed" from the feed already. 
     puts 'Importing' 
     feed.listings.each do |listing| 
     Listing.import(listing.to_hash) 
     end 

    end 
    end 

end 

正如你所看到的,我不在乎在飼料中<listings>元素。我只想要每個<listing>元素的屬性。

輸出看起來是這樣的:

Parsing 
... wait forever 
Importing (actually, I don't ever see this on the big file (1.6gb) because too much memory is used :(
+0

簡單回答你的問題:是的,有你忽視的東西。不幸的是你沒有告訴我們它是什麼。沒有人可以在他們看不到的代碼中發現內存泄漏。 – 2012-02-08 22:02:04

+0

@MichaelKay我已經添加了一個示例。謝謝 – jakeonrails 2012-02-09 00:49:43

回答

2

我叉薩克斯機,以便它使用常量內存:https://github.com/gregwebs/sax-machine

好消息:我們是在我的合併計劃改變新的維護者。 我自己和新的維護者一直在使用我的fork一年沒有問題。

+0

此分支似乎與規範存儲庫不同步,並且在兩年內未觸及。它也拋出關於根纖維屈服的錯誤... – 2013-03-14 22:46:57

+0

我也得到「(FiberError)不能從根纖維屈服」的錯誤,看起來像這個分支已經被放棄了。 – doomspork 2013-08-18 15:59:45

0

你是對的,SAXMachine急切地讀取整個文檔。看看它的處理源:https://github.com/pauldix/sax-machine/blob/master/lib/sax-machine/sax_handler.rb

要解決您的問題,我會直接使用http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/SAX/Parser.html並自己實現處理程序。

+0

感謝您確認我的懷疑。它的恥辱薩克斯機器不會做懶惰的評估或提供真正的回調機制 - 這將是出色的。 – jakeonrails 2012-02-09 18:09:25

3

這裏有一個讀者,將產生每個房源的XML來塊,這樣你就可以處理每個上市沒有將整個文檔加載到內存中

reader = Nokogiri::XML::Reader(file) 
while reader.read 
    if reader.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT and reader.name == 'listing' 
    listing = FeedListing.parse(reader.outer_xml) 
    Listing.import(listing.to_hash) 
    end 
end 

如果列表元素可以被嵌套,並且你想解析最外層的貨物清單,單一文件,你可以這樣做:

require 'rubygems' 
require 'nokogiri' 


# Monkey-patch Nokogiri to make this easier 
class Nokogiri::XML::Reader 
    def element? 
    node_type == TYPE_ELEMENT 
    end 

    def end_element? 
    node_type == TYPE_END_ELEMENT 
    end 

    def opens?(name) 
    element? && self.name == name 
    end 

    def closes?(name) 
    (end_element? && self.name == name) || 
     (self_closing? && opens?(name)) 
    end 

    def skip_until_close 
    raise "node must be TYPE_ELEMENT" unless element? 
    name_to_close = self.name 

    if self_closing? 
     # DONE! 
    else 
     level = 1 
     while read 
     level += 1 if opens?(name_to_close) 
     level -= 1 if closes?(name_to_close) 

     return if level == 0 
     end 
    end 
    end 

    def each_outer_xml(name, &block) 
    while read 
     if opens?(name) 
     yield(outer_xml) 
     skip_until_close 
     end 
    end 
    end 

end 

一旦你擁有了它的猴子打補丁,很容易對付每個單獨的上市:

open('~/feeds/large_feed.xml') do |file| 
    reader = Nokogiri::XML::Reader(file) 
    reader.each_outer_xml('listing') do |outer_xml| 

    listing = FeedListing.parse(outer_xml) 
    Listing.import(listing.to_hash) 

    end 
end 
+0

太棒了,超級好。它看起來也很快,因爲我的本地機器上的數據庫成爲導入的瓶頸。謝謝,約翰! – jakeonrails 2012-02-11 18:54:14

+0

我能夠使用這種方法解析我的大型XML文檔以及規範的薩克斯管機器寶石。謝謝! – 2013-03-14 22:48:02

3

不幸的是,現在有針對薩克斯機器的threedifferentrepos。更糟糕的是,gemspec版本沒有碰到。

儘管在Greg Weber's blog的評論,我不認爲這個代碼被集成到pauldix的或ezkl的叉。要使用該代碼的懶惰,基於光纖的版本,我認爲你需要在你的Gemfile特指gregweb's版本是這樣的:

gem 'sax-machine', :git => 'https://github.com/gregwebs/sax-machine' 
+0

看起來你是對的。 Github網絡圖(https://github.com/gregwebs/sax-machine/network)顯示Greg的更改尚未合併到規範的SAXMachine回購(由pauldix維護) – Ivar 2012-12-19 07:22:58

相關問題