处理大量数据的排序算法


12

我正在寻找一种排序算法,该算法可以处理大量数据,即,即使整个数据集无法一次保存在主存储器中,也可以使用。

我到目前为止发现的唯一候选对象是合并排序:您可以以这种方式实现该算法,即它在每次合并时都扫描您的数据集,而无需一次将所有数据保存在主存储器中。在本文的“ 与磁带机一起使用”部分中介绍了我想到的合并排序方式。

我认为这是一个很好的解决方案(复杂度为O(nx log(n)),但是我很想知道是否还有其他(可能更快)的排序算法可以处理不适合主内存的大型数据集。

编辑

这是答案所要求的更多详细信息:

  • 数据需要定期分类,例如每月一次。我不需要插入一些记录,也不需要对数据进行递增排序。
  • 我的示例文本文件大约是1 GB UTF-8文本,但是我想总体上解决该问题,即使该文件是20 GB。
  • 它不在数据库中,并且由于其他限制,它不能在数据库中。
  • 数据被其他人作为文本文件转储,我有自己的代码读取此文本文件。
  • 数据的格式是文本文件:换行符是记录分隔符。

我想到的一种可能的改进是将文件拆分为足够小的文件,以便可以在内存中排序,最后使用上面描述的算法合并所有这些文件。


1
什么样的数据?不同的数据集可能意味着最适合您目的的不同算法。
whatsisname 2012年

这是一个文本文件,我必须对行进行排序。行的长度不是固定的,但长度变化不大(每条记录大约50个字符)。
乔治

3
我不知道您的环境或您的约束,但是我将尽可能使用数据库进行排序。这是因为它几乎可以100%防止错误,并且比我的代码效率更高。
NoChance 2012年

我正在使用Linux / Java。我已经实现了合并排序,它似乎运行得很顺利。整理几百万行需要花费一些时间,但我只需要偶尔执行一次。
Giorgio

@Giorgio,您最好实现这样的算法。对于生产工作,我仍然建议您使用数据库。不仅为了提高速度,还为了提高可靠性和易于维护。
NoChance 2012年

Answers:


13

排序和搜索的规范参考是Knuth,Vol。3。从那里开始。

这本书最初是在计算机比现在小得多,速度慢得多的时候才写的,这使内存不足的分类技术比当今人们认为的更为重要。


2
感谢您的参考:我几乎可以肯定,我会在Knuth的书中找到有趣的材料。我不确定内存不足排序技术是否与今天无关。也许不是日常的日常任务,但是我可以想象仍然有很多情况需要处理非常大的数据集。
乔治

Knuth的算法总是有帮助的。例如,将合并排序与堆排序缓冲区结合在一起可能非常有效并且非常容易实现。
苏珊(Sulthan)

4
这不是一个非常有用的答案,因为所引用的材料不是免费的。对于OP,我建议使用Google搜索来寻找答案。当您可以通过在网络上查找这类信息时,无需花$ 50就能买到一本书。当然,您也可以从(ahem)某些站点免费下载此文件。几乎不值得接受的答案。
Thomas Eding

1
@ThomasEding,有一些叫做“库”的东西,其中包含大量称为“书”的过时信息存储和检索设备。“图书馆”使“书籍”可免费获得贷款。如果您的特定“图书馆”没有您要查找的特定“书籍”,他们还将提供一项称为“馆际互借”的免费服务,该服务使“图书馆”可以从另一个“图书馆”借用“书籍”,因此他们可以借给你
约翰·R·斯特罗姆

6

UNIX sort命令中的外部R-Way合并是一个不错的选择。从您的表述中,我不确定这是否就是您所说的“合并排序”算法,如果您不知道,请看一下。


谢谢。外部R-Way合并似乎与我的想法有所不同。有趣的阅​​读。
Giorgio 2012年

4

如果没有更多细节,“合并排序”可能是您将获得的最佳答案,但是您可以根据自己的需求实施更智能的方法。

例如,您是否可以简单地创建文件的内存索引,然后一次复制所有值,以缓存各种键值的位置?1/2是一次存储在内存中还是1/1000000?如果是第二个索引,则可能无法在内存中容纳索引;如果是第一个索引,则可以更有效地对两个索引进行排序,然后在最后一步将它们合并在一起。

糟糕,由于您未指定数据可能存在于数据库中,因此您可以创建一个索引表并称其为好(我猜并非如此,只是指出了这一点)您的情况对于解决此类复杂问题至关重要。

如果您只想执行一次并且正在寻找快速黑客,那么听起来好像外部合并排序将是一个不错的开始,如果您运行的是Unix(因为它显然是内置的)

如果必须保持顺序并始终添加单个记录,则必须进行插入排序(将单个记录添加到已排序的数据始终是插入排序)。

您可以控制“读取”数据的代码吗?如果是这样,那么许多形式的索引编制(而不是通过在磁盘上四处移动数据进行排序)将有助于A LOT(实际上是绝对必要的)。

所以:

  • 到位还是多个文件?
  • 是一次还是定期进行分类?
  • 比内存大多少(通过整个数据集需要多少内存负载)?
  • 它在数据库中吗?是真的吗?
  • 您是否控制读取数据的代码,还是其他人将直接转储文件?
  • 文件格式?(文本?固定记录?)
  • 我没有问过的其他特殊情况吗?

谢谢你的回答。您所说的“就地记录或多重记录”是什么意思?
Giorgio 2012年

抱歉,应该对我的回答进行校对-我的意思是多个文件。就地就地暗示固定记录大小和索引编制,此时您可能需要数据库。
Bill K

不,它没有到位:记录的大小不是固定的。我在当前的实现中使用了四个临时文件。
Giorgio

您可以用代码解释输出还是必须采用特定格式(纯文本文件?)?需要多长时间对它进行排序?每次添加或偶尔添加一次?添加某些内容时,它只是追加到末尾还是可以编写添加该内容的代码?
Bill K

每一行都可以解析为一条记录(文件是CSV文件),但是大多数字段是文本。它需要不时地进行排序(例如每月),并且用我目前的实现进行排序大约需要1个小时。对于插入行,我可以编写将行插入正确位置的代码:到目前为止,我拥有的代码要花20分钟才能编写出这样的工具。
乔治

3

如果您真的想要一个可扩展的解决方案,则应该看看TeraSort,它是带有map-reduce的标准排序实现;有关StackOverflow的更多详细信息


1
+1:有趣的链接。合并排序不是map / reduce的示例吗,map对应于对子列表进行排序,reduce对应于合并?
Giorgio

可以看到,但是您可以使用Hadoop来代替您自己编写它。
m3th0dman '11

1

您可能对存储桶排序感兴趣。平均案例性能是线性时间。

= O(n + d)n:元素数量,d =最大数量的长度(如果您对数据有直觉的话)。如果您知道最大的数字有多少个“数字”。因此,如果您有200万个6位数字=> 0(n),则为线性。


0

使用外部合并排序算法(如果您的数据是连续数据),或使用带有计数排序存储桶排序作为存储桶排序的实现(如果您的数据是离散的且均匀分布的)。

如果增量很小,可能最好的方法是构建自己的索引/映射文件。

  1. 以某种方式订购“数据库”
  2. 为每个条目(1、2、3、4,...,n)分配一个整数(最好:使用一些稀疏索引)
  3. 当增加一个增量时,只需找到一个空格,其中左边的数字小于或等于,右边的数字大于或等于(使用二进制搜索的某些修改版本应该不难)
  4. 插入,当间隙足够大时,如果没有插入:只需重新索引(不再排序):-)

0

我刚刚构建了一些称为大队列和大数组的抽象结构,以简化内存有限的一台计算机上的大数据排序和搜索任务。基本上,使用的算法类似于您上面提到的算法-外部合并排序。

我可以在一台计算机上在9个小时内对128GB数据(每个项目100字节)进行排序,然后几乎没有时间对已排序的数据进行二进制搜索。

是有关如何使用开源大队列和大数组结构搜索大数据的文章。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.