【问题标题】:How to efficiently parse large text files in Ruby如何在 Ruby 中有效地解析大型文本文件
【发布时间】:2011-06-18 07:10:17
【问题描述】:

我正在编写一个导入脚本来处理一个可能有数十万行的文件(日志文件)。使用一种非常简单的方法(如下)占用了足够的时间和内存,我觉得它随时会占用我的 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

有谁知道处理此文件中每一行的更有效(内存/cpu)方法?

更新

上面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 中的代码使用预先计算的 lambda,而不是每次都计算出计算。我想我只是假设问题在于行迭代本身,而不是每行代码。

【问题讨论】:

  • 最节省内存的方法是使用each_line 的方式。您可以更快地读取块中的文件,然后使用String#lines 来抓取各个行,同时重新加入任何跨过块边界的部分加载的行。不得不将线条分开并重新加入破损的线条。

标签: ruby text-processing


【解决方案1】:

我刚刚对一个 600,000 行的文件进行了测试,并在不到半秒的时间内迭代了该文件。我猜缓慢不是文件循环而是行解析。你也可以粘贴你的解析代码吗?

【讨论】:

  • 唯一有任何意义的代码是我将该行与一个半复杂的正则表达式匹配。正则表达式不做任何向后/向前看,它主要是一个字符一个字符的匹配。我将在上面发布相关代码的更新。
  • 哦,正则表达式只计算一次,而不是在每次迭代时计算(为了清楚起见)。
  • 看来是我的愚蠢导致了内存增长。我将匹配的结果(以及跳过的行)存储在我用来稍后进行数据库插入(或打印跳过的大小)的数组中。我知道,我很笨。 :) 现在我只是在跳过的行上执行puts,并在匹配有效时正确执行数据库插入。真正的内存永远不会超过 30mb。感谢您指出我可能只是在以愚蠢的方式做事。 :)(哦,我像你原来的答案建议的那样切换到IO.foreach)。
【解决方案2】:

如果您使用 bash(或类似的),您可能可以像这样进行优化:

在 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,这可能会导致它做一些特殊的优化。

您可能还想研究预先编写的问题解决方案,因为这样会更快。

【讨论】:

  • 在这一点上似乎比我想要的更hacky,但我会记住它。
【解决方案3】:

这个blogpost 包含几种解析大型日志文件的方法。也许这就是灵感。也看看file-tail gem

【讨论】:

    猜你喜欢
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 2014-07-11
    • 2019-04-02
    • 2011-03-25
    • 2015-04-08
    • 1970-01-01
    • 2015-10-05
    相关资源
    最近更新 更多