计算庞大的数据集(超过150亿)中的唯一URL

时间:2018-12-07 19:16:13

标签: java bigdata

我的问题如下:

  • 我得到了一个包含约1500亿个条目的URL列表。
  • 每个月我都会收到另外约1500亿的新条目。
  • 我应该删除重复项并存储其余部分。
  • 与任务相比,这应该在孤独且相当小的机器上完成(大约32-64 Gb ram可用+一堆磁盘空间)。
  • 我应该存储唯一的url(存储问题已解决)。
  • 我为此任务选择的语言是Java。

这不是面试问题或类似问题。对于业务案例,我需要这样做。

是否有一种算法可以让我实现这个目标(最好在不到一个月的时间内)?我的第一个想法是Bloom / Cuckoo过滤器,但我想尽可能保留所有URL。

1 个答案:

答案 0 :(得分:2)

我将实现合并排序,并在合并步骤中消除重复项。

您将要流传输URL,并创建可在内存中排序的大小适中的批处理。这些排序的块中的每一个都被写入磁盘。

要合并这些排序的块,请流式传输两个(或更多)文件。查看每个流中的下一个URL,并从流中获取最小的URL,并跟踪最新输出的URL。当获得下一个最小的URL时,将其与最近输出的URL进行比较-如果重复,则跳过它;否则将其输出(并记住它是最新输出)。

如果创建的已排序块使您一次打开的文件过多,请继续合并文件组,直到只有一个文件为止。此结果将没有重复。

您可能会使用Arrays.parallelSort()对初始块进行内存内排序。在输出排序后的数组元素时,可能会从这些最初排序的块中删除重复项而受益。

绝对使用缓冲的I / O。

合并多个文件时,我将创建一个优先级队列,该队列具有每个流的下一条记录以及它来自哪个流。您从优先级队列中获取下一个项目,从下一个项目所来自的流中读取下一行,并将该新行放入队列中。可以合并的流的数量将受到可以打开的文件数或所有流中缓冲I / O所需内存的限制。

要实现这一点,可能需要一页左右的代码-在一台机器上运行它很简单。但是,如果适合您的基础架构,则此问题非常适合Hadoop集群或类似的集群。如果您想在例如AWS上快速运行,您可能希望使用队列(例如AWS上的SQS)来管理要排序/合并的块-它涉及更多,但运行得更快。 / p>

其他注意事项

  1. 容错:此过程将需要很长时间才能运行;如果它在中间失败了,您是否要从头开始?您可能需要从仅流过源文件并将其分成适当大小的未排序块的步骤开始。由于涉及大量I / O,因此这一步骤本身将花费一些时间。例如,将这些块放入名为“未排序”的目录中。然后执行第二个过程,该过程将反复查找“未排序”目录,选择一个块,对其进行读取,排序,然后将其写入“已排序”目录,然后将未排序的块从“未排序”移动到“已归档”。然后进行第三步处理,该过程将从“ sorted”中读取大块并将其合并(删除重复项),并写入“ sorted1”或“ final”(取决于它是否合并所有剩余文件)。这个想法是要对事物进行结构设计,以便您始终能够不断取得进步,因此,如果服务器死机,则可以从上次中断的地方继续。
  2. 平行主义:这个过程将花费很长时间。可以并行应用到它的服务器越多,它运行得越快。您可以通过与容错几乎相同的方式来实现此目标(如果有可用的服务器)-您可以在许多计算机上并行执行排序和(中间)合并步骤(使用适当的文件锁定或其他某种方案,以便它们不尝试在相同的块上工作。