如何订购巨大的(GB大小)CSV文件?

时间:2018-05-22 15:53:43

标签: javascript node.js algorithm sorting

背景

我有一个巨大的CSV文件,有几百万行。每行都有一个我可以用来订购它的时间戳。

天真的方法

所以,我的第一种方法显然是通过将其放入内存然后排序来阅读整个内容。它可能不会像你猜的那样工作....

天真的方法v2

我的第二次尝试是遵循MapReduce背后的想法。

所以,我会将这个巨大的文件分成几个部分,并对每个部分进行排序。然后我将所有部分组合到最终文件中。

这里的问题是B部分可能有一条消息应该在A部分。所以最后,即使每个部分都是有序的,我也不能保证最终文件的顺序....

目的

我的目标是创建一个函数,当给定这个巨大的无序CSV文件时,可以创建具有相同信息的有序 CSV文件。

问题

如此大规模订购数据集的流行解决方案/算法是什么?

2 个答案:

答案 0 :(得分:7)

  

如此大规模订购数据集的流行解决方案/算法是什么?

由于您已经断定数据太大而无法在您可用的内存中进行排序/操作,因此流行的解决方案是一个数据库,它将构建基于磁盘的结构,用于管理和排序比内存中更多的数据

您可以构建自己的基于磁盘的方案,也可以使用已经完全开发,优化和维护的方案(例如,流行的数据库)。您询问的“流行”解决方案是使用数据库来管理/排序大型数据集。这正是他们为之而建的。

<强>数据库

您可以设置一个由排序键索引的表,将所有记录插入数据库,然后创建一个按键排序的游标并迭代游标,将现在排序的记录写入新文件中的一个时间。然后,完成后删除数据库。

Chunked Memory Sort,Manual Merge

或者,您可以进行分块排序,将数据分成适合内存的较小部分,对每个部分进行排序,将每个已排序的块写入磁盘,然后合并读取下一条记录的所有块从每个块到内存,找到所有块中的最低块,将其写入最终输出文件,从该块读取下一条记录并重复。使用这种方案,合并只需要在内存中有N条记录,其中N是你拥有的排序块的数量(可能小于原始的分块排序)。

正如juvian所提到的,这里概述了像这样的“外部排序”如何起作用:https://en.wikipedia.org/wiki/External_sorting

分块内存排序的一个关键方面是确定块的大小。有很多策略。最简单的可能就是根据一些简单的测试来确定你能够可靠地记录多少记录并在内存中排序,或者甚至只是猜测你确定是安全的(选择一个较小的数字来处理,这意味着你将将数据拆分为更多文件)。然后,只需将许多记录读入内存,对它们进行排序,将它们写入已知的文件名。重复该过程,直到您已读取所有记录,然后现在全部都在磁盘上具有已知文件名的临时文件中。

然后,打开每个文件,从每个文件中读取第一条记录,找到每个文件的最低记录,将其写入最终文件,从该文件中读取下一条记录并重复该过程。当您到达文件末尾时,只需将其从您正在比较的数据列表中删除,因为它现在已经完成。当没有更多数据时,你已经完成了。

仅在内存中排序键

如果所有排序键本身都适合内存,而不是相关数据,那么您可以对自己的索引进行排序。有很多不同的方法,但这是一个方案。

读取整个原始数据,将两个内容捕获到每个记录的内存中,排序键和原始文件中存储该数据的文件偏移量。然后,一旦你在内存中拥有所有排序键,就对它们进行排序。然后,逐个遍历排序的键,寻找文件中的写入点,读取该记录,将其写入输出文件,前进到下一个键并重复,直到按顺序写入每个键的数据。 / p>

BTree Key Sort

如果所有排序键都不适合内存,那么您可以获得一个基于磁盘的BTree库,它可以让您对内存中的内容进行排序。您将使用与上面相同的方案,但是您将把排序键和文件偏移量放入BTree中。

当然,将实际数据本身从文件中放入BTree只需要更进一步,然后你就拥有了一个数据库。

答案 1 :(得分:2)

我会逐行读取整个文件并将每行输出到一个临时文件夹中,按合理的时间间隔将行分组到文件中(如果间隔为一年,一天,一小时......等等)根据您的数据决定)。因此临时文件夹将包含每个间隔的单个文件(例如,对于日间隔分割,即2018-05-20.tmp,2018-05-21.tmp,2018-05-22.tmp,...等)。现在我们可以按顺序读取文件,在内存中对每个文件进行排序并输出到目标排序文件中。