2011-01-30 11 views
6

数十万行におよぶ可能性のあるファイルを処理するインポートスクリプトを作成しています(ログファイル)。非常にシンプルなアプローチ(下記)を使用することで、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のコードを、毎回計算を計算するのではなく、事前計算されたラムダを使用するようにすることができます。私は、それが問題であった行の反復そのものであり、行単位のコードではないと仮定したと思います。

+0

最も効率的な方法は 'each_line'でそれをやっている方法です。より速いブロックでファイルを読み込み、 'String#lines'を使用して個々の行を取得し、ブロック境界を越えて部分的に読み込まれた行に再結合することができます。それは、ラインを分割して壊れたものに戻らなければならない洗濯になります。 –

答えて

5

私はちょうど600,000行のファイルに対してテストを行い、0.5秒未満でファイルを反復処理しました。私は遅さがファイルのループではなく、行の解析ではないと推測しています。パースコードも貼り付けることができますか?

+0

重要な意味を持つ唯一のコードは、私が半複雑な正規表現と一致していることです。正規表現は後方/前方を見ていません。ほとんどの場合、char-by-charと一致します。上記のアップデートを関連コードとともに掲示します。 – localshred

+0

ああ、正規表現は各繰り返しではなく、一度計算されます(クリアするだけです)。 – localshred

+0

記憶の成長を引き起こしていたのは私の愚かさでした。私は後でdb挿入(またはスキップのサイズを印刷)するために使用していた配列に、一致する結果(およびスキップされた行)を格納していました。私は知っている、私はばかだ。:)今、私はちょうどスキップされた行に 'puts'を行い、マッチが有効なときにdb insertを実行しています。本当のmemは30MBを超えることはありません。私はおそらくちょうど愚かなやり方で物事をしていたことを指摘してくれてありがとう。 :)(オハイオ州と私はあなたの元の答えが示唆したように 'IO.foreach'に切り替えました)。 – localshred

1

あなたはbashの(または類似)を使用している場合はこのように最適化することができるかもしれない:

input.rbで:bashで、その後

while x = gets 
     # Parse 
end 

cat nginx.log | ruby -n input.rb 

-nフラグはrubyにassume 'while gets(); ... end' loop around your scriptを通知します。これにより、最適化するために特別な処理が行われる可能性があります。

また、問題の事前解決策を調べることもできます。これは高速になるためです。

+0

この時点で私が望むよりも少しハッキリに見えますが、私はそれを念頭に置いています。 – localshred

4

このblogpostには、大きなログファイルを解析するためのいくつかのアプローチが含まれています。たぶんインスピレーションですまた、を参照してくださいfile-tail gem

関連する問題