3

介绍

我有一个有多个表的应用程序,有些有关联,有些没有关联。

一些表格将需要容纳大约 100,000 个条目。

该应用程序在 Ruby 1.9 上使用 Rails 3.2,并托管在 Heroku 上。如果需要,我可以接触到工人。

有问题的要求

该应用程序的一个重要要求是允许用户将数据导出为 CSV - 对此的要求是允许用户过滤他们想要导出的数据,但我现在并不担心,正如您将看到的下面的数据,我已经硬编码了要导出的数据,但这确实排除了创建一个 rake 任务来导出整个表。

此外,实现的方法必须考虑到允许多个表使用,以避免不必要的代码重复。

当前解决方案

我正在我的应用程序中实现延迟作业并在作业中执行 CSV 生成。在这样做的同时,我正在关注“abdullah”的http://www.ayokasystems.com/blog/delegating-long-running-jobs-in-rails/上的解决方案。

想法是生成 CSV 格式的数据并将其保存在 UserJobs 表的 LONGTEXT 字段中,以允许用户在完成后和将来的时间下载。

问题

上述教程中使用的方法在我的应用程序中运行良好,直到我一次运行 100,000 条记录的工作。为了克服这个问题,我尝试将很酷的 find_each 函数添加到 perform 方法中,但是延迟的作业工作者每次尝试处理它时都会报告一个错误:

[Worker(host:*** pid:18637)] ReportJob failed with NoMethodError: undefined method `each' for #<Title:0x007ff20c1ec1b0> - 0 failed attempts
[Worker(host:*** pid:18637)] ReportJob failed with NoMethodError: undefined method `each' for #<Title:0x007ff20ec47f18> - 1 failed attempts
[Worker(host:*** pid:18637)] 2 jobs processed at 10.5219 j/s, 2 failed ... 

我的 perform 方法代码是:

def perform
  Title.find_each do |titles|
    csv_data = CSV.generate do |csv|
      titles.each do |t|
        csv << t.to_csv
      end
    end
    user_job = UserJob.find(user_job_id)
    user_job.update_attribute :data, csv_data
  end
end

任何人都可以看到问题可能是什么,我想我在循环事物的方式上犯了一个愚蠢的错误。

我对如何完成相关要求的任何其他建议持开放态度,但请记住我对 Heroku 的限制。

4

2 回答 2

3

您正在尝试使用each进行迭代,但在这种情况下,标题是标题的实例(不是数组)。

csv_vals = []
columns = [:name, :release_date, :studio]

Title.find_each(:select => columns) do |title| 
  columns.each {|value| csv_vals << "#{title[value]}"}
end

# comma separated string 
csv_string = csv_vals.join(',')

有更优雅的方式来制定 CSV 字符串,但我懒得做实验。

重要的是您只在需要的列上执行 SELECT。对于 100 000 条记录,这会大大减少带宽 DB 通信。只需find_each 即可获得每一行的所有列,而您不需要它们。

于 2012-04-20T12:05:28.517 回答
1

find_each为块产生单个记录,而不是集合,因此您在调用each单个记录时出错。看看find_in_batches,或者修复您的代码以使用单个记录:

Title.find_each do |title|
  CSV.generate do |csv|
    csv << title.to_csv
  end
  user_job = UserJob.find(user_job_id)
  user_job.update_attribute :data, csv_data
end
于 2012-04-20T11:52:07.427 回答