我有大型 CSV 数据集(超过 1000 万行)需要处理。我有两个其他文件需要引用输出 - 它们包含的数据放大了我们对 CSV 文件中数百万行的了解。目标是输出一个新的 CSV 文件,其中每条记录都与来自其他文件的附加信息合并。
假设大型 CSV 文件有交易,但客户信息和账单信息记录在另外两个文件中,我们想要输出一个新的 CSV,其中每笔交易都链接到客户 ID 和账户 ID 等。
一位同事有一个用 Java 编写的功能程序来执行此操作,但速度很慢。原因是数百万行的 CSV 文件显然要遍历很多很多次。
我的问题是——是的,我已经开始了——我应该如何在 Ruby 中处理这个问题?目标是让它更快(现在 18 小时以上,CPU 事件很少)
我可以将这么多记录加载到内存中吗?如果可以,我应该怎么做?
我知道这有点含糊。只是在寻找想法,因为这对我来说有点新鲜。
最佳答案
这是我编写的一些 ruby 代码,用于处理大型 csv 文件(在我的例子中为 ~180mb)。
https://gist.github.com/1323865
一个标准的 FasterCSV.parse 将其全部拉入内存需要一个多小时。这将它缩短到大约 10 分钟。
相关部分是这样的:
lines = []
IO.foreach('/tmp/zendesk_tickets.csv') do |line|
lines << line
if lines.size >= 1000
lines = FasterCSV.parse(lines.join) rescue next
store lines
lines = []
end
end
store lines
IO.foreach 不会将整个文件加载到内存中,只是通过一个缓冲区逐步执行它。当它达到 1000 行时,它会尝试解析 csv 并仅插入这些行。一个棘手的部分是“下一个救援”。如果您的 CSV 包含一些跨多行的字段,您可能需要多抓取几行以获得有效的可解析 csv 字符串。否则,您所在的线路可能位于田野的中间。
在要点中,您可以看到另一个不错的优化,它使用 MySQL 的更新 ON DUPLICATE KEY
。这允许您批量插入,如果检测到重复键,它只会覆盖该行中的值,而不是插入新行。你可以把它想象成一个查询中的创建/更新。您需要在至少一列上设置唯一索引才能使其正常工作。
关于ruby - 快速处理大量 CSV 数据的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5557157/