Wie effizient analysieren Sie große text-Dateien in Ruby
Schreibe ich ein import-script, dass eine Datei verarbeitet hat, dass potenziell Hunderte von tausenden von Linien (log-Datei). Mit einem sehr einfachen Ansatz (unten) nahmen sich genügend Zeit und Erinnerung, die ich fühlte, dass es würde mein MBP in jedem moment, so dass ich getötet der Prozess.
#...
File.open(file, 'r') do |f|
f.each_line do |line|
# do stuff here to line
end
end
Diese Datei hat insbesondere 642,868 Linien:
$ wc -l nginx.log /code/src/myimport
642868 ../nginx.log
Kennt jemand eine effizientere (Speicher/cpu) Weg, um jede Zeile in dieser Datei?
UPDATE
Den code innerhalb der f.each_line
von oben ist einfach ein passender regex-gegen die Linie. Wenn das Spiel ausfällt, ich die Zeile hinzufügen, um eine @skipped
array. Wenn es geht, ich format die Spiele in einen hash (sortiert nach den "Feldern" des Spiels) und fügen es ein @results
array.
# regex built in `def initialize` (not on each line iteration)
@regex = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - (.{0})- \[([^\]]+?)\] "(GET|POST|PUT|DELETE) ([^\s]+?) (HTTP\/1\.1)" (\d+) (\d+) "-" "(.*)"/
#... loop lines
match = line.match(@regex)
if match.nil?
@skipped << line
else
@results << convert_to_hash(match)
end
Bin ich völlig offen, da dies ein ineffizienter Prozess. Ich könnte den code innerhalb von convert_to_hash
verwenden Sie eine vorausberechnete lambda anstelle von herauszufinden, die Berechnung jedes mal. Ich denke, ich nahm an, es war die Linie iteration und für sich war das problem, nicht die pro-line-code.
each_line
. Sie konnte Lesen, Sie die Datei in Blöcke, die schneller ist, dann verwenden Sie String#lines
zu greifen einzelne Leitungen mit der Wiedervereinigung teilweise geladen Linien, überquerte den block hinweg. Es wird zum waschen mit nach split aus, die Linien und wieder gebrochen diejenigen.InformationsquelleAutor localshred | 2011-01-30
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich habe gerade einen test auf einem 600.000-Datei und es iteriert über die Datei in weniger als einer halben Sekunde. Ich vermute, dass die Langsamkeit ist nicht in der Datei Loopen, aber das line-parsing. Können Sie fügen Sie Ihre parse code auch?
Oh, und die regex einmal berechnet wird, nicht bei jeder iteration (nur um klar zu sein).
Es scheint, dass es war meine Dummheit, was das Wachstum Speicher. Ich war die Speicherung der abgestimmten Ergebnisse (und auch die übersprungenen Zeilen) in array-dass ich im Begriff war zu tun, db fügt später (oder drucken Sie die Größe der überspringt). Ich weiß, ich bin dumm. 🙂 Jetzt bin ich gerade dabei eine
puts
auf die übersprungenen Zeilen und macht die db einfügen Recht, wenn das match gültig ist. Die real mem geht nie über 30mb. Danke für den Hinweis, ich war wohl zu einfach, die Dinge in eine dumme Art und Weise. 🙂 (Oh, und ich wechselte zuIO.foreach
wie deine ursprüngliche Antwort vorgeschlagen).InformationsquelleAutor
Diese Beitrag umfasst mehrere Ansätze zur Analyse von großen log-Dateien. Vielleicht ist das ja eine inspiration. Auch haben Sie einen Blick auf die Datei-Schwanz gem
InformationsquelleAutor hukl
Wenn Sie die bash benutzen (oder ähnliches) vielleicht sind Sie in der Lage sein, zu optimieren, wie dieses:
In-Eingang.rb:
dann in der bash:
Den
-n
flag erzählt rubyassume 'while gets(); ... end' loop around your script
, die möglicherweise dazu führen, es zu tun, etwas besonderes zu optimieren.Möchten Sie vielleicht auch einen Blick in eine vorgefertigte Lösung für das problem, wie das wird schneller sein.
InformationsquelleAutor Andrew Amis