2012-02-08 10 views
5

मेरे पास 1.6 जीबी एक्सएमएल फ़ाइल है, और जब मैं सैक्स मशीन के साथ इसे पार्स करता हूं तो ऐसा लगता है कि यह स्ट्रीमिंग या फाइलों में फाइल नहीं खा रहा है - बल्कि यह प्रतीत होता है पूरी फ़ाइल को स्मृति में लोड करने के लिए (या हो सकता है कि कहीं मेमोरी लीक हो?) क्योंकि मेरी रूबी प्रक्रिया 2.5 जीबी रैम के ऊपर चढ़ती है। मुझे नहीं पता कि यह कहां बढ़ रहा है क्योंकि मैं स्मृति से बाहर भाग गया।सैक्समाचिन के साथ बड़ी फ़ाइल को पार्स करना पूरी फ़ाइल को स्मृति में लोड कर रहा है

एक छोटी फ़ाइल (50 एमबी) पर यह पूरी फ़ाइल लोड हो रहा है। मेरा कार्य xml फ़ाइल में रिकॉर्ड्स पर पुनरावृत्त करता है और प्रत्येक रिकॉर्ड को डेटाबेस में सहेजता है। इसमें "idling" के लगभग 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

सरल जवाब आपके सवाल का: हाँ, वहाँ कुछ आप को अनदेखा कर रहे है। दुर्भाग्य से आपने हमें यह नहीं बताया है कि यह क्या है। कोई भी कोड में मेमोरी लीक नहीं ढूंढ सकता है जिसे वे नहीं देख सकते हैं। –

+0

@ माइकलके मैंने एक नमूना जोड़ा है। धन्यवाद – jakeonrails

उत्तर

2

मैं सैक्स मशीन काँटेदार इतना है कि यह निरंतर स्मृति का उपयोग करता है: https://github.com/gregwebs/sax-machine

अच्छी खबर: वहाँ एक नया मेंटेनर कि अपने परिवर्तनों को मर्ज करने की योजना बना रहा है। स्वयं और नया रखरखाव अब एक साल के लिए बिना किसी समस्या के मेरे कांटे का उपयोग कर रहा है।

+0

यह शाखा कैनोलिक रिपोजिटरी के साथ सिंक हो गई है और दो साल में छुआ नहीं गया है। यह रूट फाइबर से उपज के बारे में त्रुटियों को फेंक रहा था ... –

+0

मुझे भी "फाइबर त्रुटि" रूट फाइबर से उत्पन्न नहीं हो सकता है "त्रुटि, ऐसा लगता है कि इस शाखा को छोड़ दिया गया है। – doomspork

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

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

+0

मैं इस दृष्टिकोण का उपयोग कर कैनोनिकल सैक्स-मशीन मणि के साथ अपने बड़े एक्सएमएल दस्तावेज़ को पार्स करने में सक्षम था। धन्यवाद! –

3

दुर्भाग्य से अब threedifferentrepos sax-machine के लिए हैं। और बदतर, gemspec संस्करण टक्कर नहीं लगी थी।

Greg Weber's blog पर टिप्पणी के बावजूद, मुझे नहीं लगता कि यह कोड पॉडिक्स या ईज़ीएलएल के कांटे में एकीकृत किया गया था।कोड के आलसी, फाइबर आधारित संस्करण का उपयोग करने के लिए, मुझे लगता है कि आप विशेष रूप से इस तरह से अपनी gemfile में gregweb's संस्करण को संदर्भित करने की जरूरत है:

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

ऐसा लगता है कि आप सही हैं। गीथब नेटवर्क ग्राफ़ (https://github.com/gregwebs/sax-machine/network) दिखाता है कि ग्रेग के परिवर्तनों को कैननिकल सैक्समाचिन रेपो (पाउल्डिक्स द्वारा बनाए रखा गया) में विलय नहीं किया गया है। – Ivar

संबंधित मुद्दे

 संबंधित मुद्दे