数十万行におよぶ可能性のあるファイルを処理するインポートスクリプトを作成しています(ログファイル)。非常にシンプルなアプローチ(下記)を使用することで、MBPをいつでも取り出せるような時間と記憶が得られたので、私はそのプロセスを犠牲にしました。 Rubyで大きなテキストファイルを効率的に解析する方法
#...
File.open(file, 'r') do |f|
f.each_line do |line|
# do stuff here to line
end
end
特に、このファイルには、642868行があります。
$ wc -l nginx.log /code/src/myimport
642868 ../nginx.log
は、誰もがこのファイルの各行を処理するため、より効率的な(メモリ/ CPU)方法を知っていますか?
UPDATE
上記からf.each_line
の内部コードは、単に行に対して正規表現に一致しています。一致が失敗した場合は、@skipped
配列にその行を追加します。それが合格すると、マッチをハッシュ(マッチの "フィールド"をキーとする)にフォーマットし、それを@results
配列に追加します。
# 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
これは非効率的なプロセスです。 convert_to_hash
のコードを、毎回計算を計算するのではなく、事前計算されたラムダを使用するようにすることができます。私は、それが問題であった行の反復そのものであり、行単位のコードではないと仮定したと思います。
最も効率的な方法は 'each_line'でそれをやっている方法です。より速いブロックでファイルを読み込み、 'String#lines'を使用して個々の行を取得し、ブロック境界を越えて部分的に読み込まれた行に再結合することができます。それは、ラインを分割して壊れたものに戻らなければならない洗濯になります。 –