Как эффективно анализировать большие текстовые файлы в Ruby - PullRequest
6 голосов
/ 31 января 2011

Я пишу сценарий импорта, который обрабатывает файл с потенциально сотнями тысяч строк (файл журнала). Использование очень простого подхода (см. Ниже) заняло достаточно времени и памяти, и я чувствовал, что в любой момент это может привести к потере MBP, поэтому я убил процесс.

#...
File.open(file, 'r') do |f|
  f.each_line do |line|
    # do stuff here to line
  end
end

Этот файл, в частности, содержит 642 868 строк:

$ wc -l nginx.log                                                                                                                                        /code/src/myimport
  642868 ../nginx.log

Кто-нибудь знает более эффективный (память / процессор) способ обработки каждой строки в этом файле?

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 использовать предварительно вычисленную лямбду вместо того, чтобы вычислять вычисления каждый раз. Наверное, я просто предположил, что проблема заключалась в самой итерации строки, а не в коде для каждой строки.

Ответы [ 3 ]

5 голосов
/ 31 января 2011

Я только что проверил файл с 600 000 строк, и он перебрал файл менее чем за полсекунды. Я предполагаю, что медлительность не в цикле файла, а в разборе строки. Вы можете также вставить свой код разбора?

4 голосов
/ 13 февраля 2011

Этот blogpost включает в себя несколько подходов к анализу больших файлов журнала. Может быть, это вдохновение. Также взгляните на file-tail gem

1 голос
/ 31 января 2011

Если вы используете bash (или подобный), вы можете оптимизировать его следующим образом:

In input.rb:

 while x = gets
      # Parse
 end

, затем bash:

 cat nginx.log | ruby -n input.rb

Флаг -n указывает ruby ​​на assume 'while gets(); ... end' loop around your script, что может заставить его сделать что-то особенное для оптимизации.

Возможно, вы захотите найти заранее написанное решение проблемы, так как это будет быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...