处理大量的CSV文件

时间:2016-07-12 14:40:31

标签: ruby performance csv

我会尝试扩展我的问题标题。我从事ruby项目。我必须处理存储在CSV文件中的大量数据(大约120000)。我必须阅读这些数据,处理并放入DB。现在需要几天时间。我必须加快速度。问题是,有时在处理过程中我会遇到一些异常,我必须重复整个导入过程。我认为更重要的是提高性能,而不是使用少量数据查找错误。现在我坚持使用CSV文件。我决定对处理脚本进行基准测试以找到瓶颈并改进从CSV加载数据。我看到以下步骤:

  1. 基准并修复最有问题的瓶颈
  2. 可能会从CSV和处理中拆分加载。例如,在那里创建单独的表并加载数据。在下一步中加载此数据,处理并放入右表。
  3. 介绍从CSV加载数据的线程
  4. 现在我使用标准的ruby CSV库。你推荐一些更好的宝石吗?

    如果你们中的一些人对类似问题很熟悉,那么很高兴认识你们。

    编辑:

    数据库:postgrees

    系统:linux

3 个答案:

答案 0 :(得分:3)

我没有机会亲自测试,但我明确地通过这篇文章,似乎做了这个工作。

https://infinum.co/the-capsized-eight/articles/how-to-efficiently-process-large-excel-files-using-ruby

您必须适应使用CSV而不是XLSX。 如果该站点将在此处停止代码,以供将来参考。 它的工作原理是在数据库中同时写入BATCH_IMPORT_SIZE记录,应该给予巨大的利润。

class ExcelDataParser
  def initialize(file_path)
    @file_path = file_path
    @records = []
    @counter = 1
  end

  BATCH_IMPORT_SIZE = 1000

  def call
    rows.each do |row|
      increment_counter
      records << build_new_record(row)
      import_records if reached_batch_import_size? || reached_end_of_file?
    end
  end

  private

  attr_reader :file_path, :records
  attr_accessor :counter

  def book
    @book ||= Creek::Book.new(file_path)
  end

  # in this example, we assume that the
  # content is in the first Excel sheet
  def rows
    @rows ||= book.sheets.first.rows
  end

  def increment_counter
    self.counter += 1
  end

  def row_count
    @row_count ||= rows.count
  end

  def build_new_record(row)
    # only build a new record without saving it
    RecordModel.new(...)
  end

  def import_records
    # save multiple records using activerecord-import gem
    RecordModel.import(records)

    # clear records array
    records.clear
  end

  def reached_batch_import_size?
    (counter % BATCH_IMPORT_SIZE).zero?
  end

  def reached_end_of_file?
    counter == row_count
  end
end

https://infinum.co/the-capsized-eight/articles/how-to-efficiently-process-large-excel-files-using-ruby

答案 1 :(得分:1)

有几种方法可以解决这个问题。我个人会推荐SmarterCSV,这使得使用阵列哈希处理CSV更快更容易。如果可能的话,你肯定应该分开工作,或者使用Redis

制作要处理的文件队列并分批处理

答案 2 :(得分:1)

确保您的Ruby脚本可以处理作为参数给出的多个文件,即您可以像这样运行它:

script.rb abc.csv def.csv xyz.csv

然后使用这样的GNU Parallel并行化它以保持所有CPU内核忙碌:

find . -name \*.csv -print0 | parallel -0 -X script.rb

-X将尽可能多的CSV文件传递给Ruby作业,而不会超出命令行的最大长度。如果您希望-j 8一次运行8个作业,则可以在parallel之后添加GNU Parallel,并且可以使用--eta来获取预计到达/结束时间:

 find . -name \*.csv -print0 | parallel -0 -X -j 8 --eta script.rb

默认情况下,GNU Parallel将与CPU内核并行运行多个作业。