2011-07-13 11 views
12

Próbuję użyć Nokogiri Ruby do parsowania dużych (1 GB lub więcej) plików XML. Testuję kod na mniejszym pliku, zawierającym tylko 4 rekordy available here. Używam Nokogiri w wersji 1.5.0, Ruby 1.8.7 na Ubuntu 10.10. Ponieważ nie rozumiem bardzo dobrze języka SAX, próbuję rozpocząć Nokogiri :: XML :: Reader.Jak używać programu Nokogiri :: XML :: Reader do analizowania dużych plików XML?

Moja pierwsza próba, aby pobrać zawartość tagu PMID, wygląda następująco:

#!/usr/bin/ruby 
require "rubygems" 
require "nokogiri" 

file = ARGV[0] 
reader = Nokogiri::XML::Reader(File.open(file)) 
p  = [] 
reader.each do |node| 
    if node.name == "PMID" 
    p << node.inner_xml 
    end 
end 

puts p.inspect 

Oto co mam nadzieję zobaczyć:

["21714156", "21693734", "21692271", "21692260"] 

Oto, co rzeczywiście widział:

["21714156", "", "21693734", "", "21692271", "", "21692260", ""] 

Wygląda na to, że z jakiegoś powodu mój kod znajduje lub generuje dodatkowy, pusty znacznik PMID dla każdego wystąpienia e PMID. Albo to albo inner_xml nie działa tak, jak myślałem.

Byłbym wdzięczny, gdyby ktoś mógł potwierdzić, że mój kod i dane generują wyświetlany wynik i sugerują, gdzie idę źle.

+0

W "dawnych czasach", zanim mieliśmy hosty z wieloma GB pamięci RAM, martwiliśmy się ładowaniem jednej lub dwóch GB treści. Teraz, chyba że istnieje ryzyko otrzymania nieoczekiwanego pliku, który pochłonąłby całą dostępną pamięć RAM, spróbowałbym pozwolić Nokogiri i Ruby na pobieranie pełnowymiarowego pliku. Tak, 1GB to dużo tekstu, ale w systemie 8GB lub 16GB to nic. Zobacz, czy czas ładowania i przetwarzania się poprawi, czy też nie, ponieważ alokacja pamięci i odśmiecanie mogą wpływać na szybkość; Korzystanie z modelu SAX może pomóc w tym przypadku, ale wolę załadować go i traktować jak DOM. –

+0

Prędkość jest większym problemem niż pamięć RAM. Próbowałem na przykład parsowania z Hpricot (moja preferowana biblioteka) na współdzielonym serwerze z 96 GB pamięci RAM: 72 minuty. – neilfws

+0

Nie śledziłem Hpricota przez kilka lat; Dużo go używałem, ale natrafiłem na pewne problemy, w których eksplodował konsekwentnie w chwalebny sposób, a Nokogiri nie, więc przestawiłem się i nie oglądałem się za siebie. 72 minuty to długi bieg. Możesz spróbować uruchomić profilera i zobaczyć, czy to coś odkrywa. W przeciwnym razie, podsumuj kod i XML i opublikuj go tutaj, a postaramy się pomóc przyśpieszyć. –

Odpowiedz

18

Każdy element w strumieniu przechodzi przez dwa zdarzenia: jeden do otwarcia elementu i drugi do zamknięcia. Impreza otwarcia będzie mieć

node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT 

a zdarzenie zamknięcia będą miały

node.node_type == Nokogiri::XML::Reader::TYPE_END_ELEMENT 

Puste struny widzisz to tylko element zamknięcia imprezy. Pamiętaj, że podczas analizowania SAX zasadniczo przechodzisz przez drzewo, więc potrzebujesz drugiego zdarzenia, aby poinformować cię, kiedy wracasz i zamykasz element.

Prawdopodobnie chcesz coś bardziej jak to:

reader.each do |node| 
    if node.name == "PMID" && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT 
    p << node.inner_xml 
    end 
end 

Albo:

reader.each do |node| 
    next if node.name  != 'PMID' 
    next if node.node_type != Nokogiri::XML::Reader::TYPE_ELEMENT 
    p << node.inner_xml 
end 

lub jakąś inną odmianę w tej sprawie.

+0

Twoje pierwsze rozwiązanie działa; Dziękuję bardzo. – neilfws

+0

dlaczego nie wypróbować tego - https://github.com/amolpujari/reading-huge-xml –

Powiązane problemy