Ich habe eine große XML-Datei (ungefähr 10K Zeilen), die ich regelmäßig in diesem Format parsen muss:
%Vor%Was ich tun möchte, ist, jeden einzelnen Knoten mit nokogiri zu analysieren, um die Anzahl der Objekte in einer Kategorie zu zählen. Dann möchte ich diese Zahl von total_count subtrahieren, um eine Ausgabe zu bekommen, die liest "Count of Interest_Category: n, Zählung von allem anderen: z".
Das ist jetzt mein Code:
%Vor%Das scheint zu funktionieren, ist aber sehr langsam! Ich spreche mehr als 10 Minuten für 10.000 Artikel. Gibt es einen besseren Weg, dies zu tun? Tue ich etwas in einer nicht optimalen Weise?
Sie können die Ausführungszeit erheblich verkürzen, indem Sie Ihren Code wie folgt ändern. Ändern Sie einfach die "99" in die Kategorie, die Sie überprüfen möchten.:
%Vor%Dies dauerte ungefähr drei Sekunden an meinem Gerät. Ich denke, ein Schlüsselfehler, den Sie gemacht haben, war, dass Sie die "Items" iteriert haben, anstatt eine Sammlung der Item-Knoten zu erstellen. Das hat Ihren Iterationscode umständlich und langsam gemacht.
Hier ist ein Beispiel zum Vergleich einer SAX-Parser-Zählung mit einer DOM-basierten Zählung, die 500.000 <item>
s mit einer von sieben Kategorien zählt. Zuerst die Ausgabe:
Erstellen Sie eine XML-Datei: 1.7s
Zählen über SAX: 12.9s
Erstellen DOM: 1.6s
Zählen über DOM: 2.5s
Beide Techniken erzeugen den gleichen Hashwert und zählen die Anzahl der gesehenen Kategorien:
%Vor% Die SAX-Version benötigt 12,9 Sekunden zum Zählen und Kategorisieren, während die DOM-Version nur 1,6 Sekunden benötigt, um die DOM-Elemente zu erstellen und 2,5 Sekunden mehr, um alle <cat>
-Werte zu finden und zu kategorisieren. Die DOM-Version ist etwa 3x so schnell!
... aber das ist nicht die ganze Geschichte. Wir müssen uns auch die RAM-Nutzung ansehen.
Ich hatte genug Speicher auf meinem Computer, um 1.000.000 Elemente zu verwalten, aber bei 2.000.000 lief mir der Arbeitsspeicher aus und ich musste anfangen, virtuellen Speicher zu verwenden. Selbst mit einer SSD und einer schnellen Maschine ließ ich den DOM-Code fast zehn Minuten lang laufen, bevor er ihn schließlich tötete.
Es ist sehr wahrscheinlich, dass die langen Zeiten, die Sie berichten, darauf zurückzuführen sind, dass Ihnen der Arbeitsspeicher knapp wird und Sie die Festplatte kontinuierlich als Teil des virtuellen Speichers nutzen. Wenn Sie das DOM in den Speicher einbauen können, verwenden Sie es, da es FAST ist. Wenn Sie jedoch nicht können, müssen Sie wirklich die SAX-Version verwenden.
Hier ist der Testcode:
%Vor%Wenn wir einen Teil der Teststruktur entfernen, sieht der DOM-basierte Zähler wie folgt aus:
%Vor%Zuerst konzentrieren wir uns auf diesen Code:
%Vor%Wenn wir eine neue Instanz dieser Klasse erstellen, erhalten wir ein Objekt mit einem Hash, der für alle Werte standardmäßig 0 ist, und ein paar Methoden, die darauf aufgerufen werden können. Der SAX-Parser ruft diese Methoden auf, während er durch das Dokument läuft.
Jedes Mal, wenn der SAX-Parser ein neues Element sieht, ruft er die Methode start_element
für diese Klasse auf. Wenn das passiert, setzen wir ein Flag, basierend darauf, ob dieses Element den Namen "cat" hat oder nicht (damit wir den Namen später finden können).
Jedes Mal, wenn der SAX-Parser ein Stück Text aufschlitzt, ruft er die Methode characters
unseres Objekts auf. Wenn das passiert, überprüfen wir, ob das letzte Element, das wir gesehen haben, eine Kategorie war (d. H. Wenn @count
auf true
gesetzt wurde); Wenn ja, verwenden wir den Wert dieses Textknotens als Kategorienamen und fügen einen zu unserem Zähler hinzu.
Um unser benutzerdefiniertes Objekt mit dem SAX-Parser von Nokogiri zu verwenden, machen wir folgendes:
%Vor%Ich würde empfehlen, einen SAX-Parser anstelle eines DOM-Parsers für eine so große Datei zu verwenden. Nokogiri hat einen schönen SAX-Parser eingebaut: Ссылка
Die SAX-Methode ist gut für große Dateien, einfach weil sie keinen riesigen DOM-Baum erzeugt, was in Ihrem Fall zu viel ist; Sie können eigene Strukturen aufbauen, wenn Ereignisse ausgelöst werden (z. B. zum Zählen von Knoten).
Schau dir Greg Webers Version von Paul Dix 'Saxophon-Juwel an: Ссылка
Parsing große Datei mit SaxMachine scheint die gesamte Datei in den Speicher zu laden
Sax-Maschine macht den Code viel einfacher; Gregs Variante lässt es streamen.