快速处理大量CSV数据的最佳方式

我有需要处理的大型CSV数据集(10M +行)。 我还有两个需要为输出引用的文件 – 它们包含的数据可以放大我们对CSV文件中数百万行的了解。 目标是输出一个新的CSV文件,其中每个记录与其他文件中的附加信息合并。

想象一下,大型CSV文件有交易,但客户信息和账单信息记录在另外两个文件中,我们想要输出一个新的CSV,每个交易都链接到客户ID和账户ID等。

一位同事有一个用Java编写的function程序来执行此操作,但速度非常慢。 原因是具有数百万行的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优化优化。 这允许您批量插入,如果检测到重复键,它只是覆盖该行中的值而不是插入新行。 您可以将其视为一个查询中的创建/更新。 您需要在至少一列上设置唯一索引才能使其生效。

10M +行听起来并不是那么多。 如果你可以预先加载文件的内容并将内存中的数据与合适的数据结构相匹配(你需要在某些时候使用地图),你就不必一遍又一遍地运行CSV文件。 文件访问速度很

两个相当快的选择:

  1. 将您的数据放入sqlite DB。 然后,这是一个简单的查询,使用一对join ,比你自己编写的任何东西都要快 – SQL非常适合这类任务。

  2. 假设您的其他CSV文件足够小以适应RAM,您可以使用客户ID作为密钥将所有内容读入哈希,然后在处理具有10 + M记录的主文件时查找该哈希值。 请注意,只需要将查找数据放入RAM,主列表可以在小分支中处理。

我的经验是,使用Ruby,准备实际有效负载的内存使用量约为10倍。 当然,对于当前的RAM量,如果进程一次只加载一个文件,即使乘以10,10MB几乎可以忽略不计:)

如果您可以一次读取一行(使用File实例很容易),您可以使用FasterCSV并一次写一行。 这将使内存消耗O(1 )而不是O(n) 。 但是对于10兆字节的文件,您可以将该文件粘贴到内存中,并在一次通过中将其写入CSV,在任何给定时间只给出几个进程。

如果您编写了Java程序,请确保使用NIO库。 它们比默认速度快。 我之前使用NIO库处理了500,000行的文本文件。