这是很多记录 ;-) 大约 1,000,000,000 条。最好聪明点……
记录的性质是不确定的:我们是否只是通过顺序读取它们来发现它们,或者是否有某种索引,或者它们是否作为文件存储在不同的目录中?问题中还没有指定 dbms 的可用性,我们可以将其用于类似索引的数据(而不是必须用我们自己的代码对其进行排序)。此外,对重复数量的 [甚至粗略] 概念将有助于将一些选择导向一个有效的过程。
如果不存在索引,我们可以/应该创建一个;这可以在第一次通过数据时完成。相同的传递将用于为每条记录(或可能,出于效率目的,为记录的前几百个字节)生成各种类型的消息摘要(散列)。
总体思路是快速生成可用于识别可能重复的索引,并最终确定实际重复的列表,可能通过并行处理。
索引中有用的信息是:
- 记录长度
- 文本的前几个字节
- 哈希码(更多内容见下文)
- 还有文件中的偏移量或任何指向数据的指针,但当然与上述 3 个元素不同,这不能用于识别潜在的匹配项。
哈希的选择很关键:应该以牺牲完美分布的算法为代价来支持快速算法;每个记录的散列字节数也是一个折衷方案,可能 100 到 200 个字节(即平均记录大小的大约 10% 到 20%)是一个不错的值,具体取决于预期的重复率和节省的时间这提供了(与散列整个记录相比)。 (见下面的编辑)
一旦有了这样的索引,我们就可以[相对快速/毫不费力地]获得可能重复的计数;基于此结果,如果认为选择性不够,可以进行旨在提高索引质量的第二次遍历(忽略容易被视为唯一的记录)。第二遍可以在整个记录(不包括第一个散列的前 x 个字节)或记录的另一个子集上计算另一个散列。请注意,多亏了索引,如果可能,第二次传递可以是多线程的。
第二次或最后一次通过需要对一组可能匹配(相同长度、相同哈希码、相同的前 x 个字节)中的记录进行排序。正如 Pax Diablo 所描述的那样,这可以实现,索引的优点是这种操作可以再次是多线程的,并且涉及更小的集合(其中很多)。 已添加:Nick Johnson 再次强调,如果我们使用长哈希码(他建议使用 128 字节长的 SHA1),可能不需要第二遍。假设对记录进行部分散列没有任何好处,这是一个非常合理的解决方案,因为索引可以驻留在磁盘上,但比我们排序/存储整个记录时更快地排序和存储。
编辑:Nick Johnson 提出了一个很好的观点,即磁盘存储中的寻道延迟可能会导致普通顺序读取更快,而瓶颈是磁盘 I /O 限制,并发运行的快速哈希函数可能实际上比顺序读取更快,因此不会添加到整个过程中。这是一种可能的可能性(特别是如果有效地需要顺序读取来检测每条记录的开始/结束等),这就是为什么我通过写“取决于这提供的时间节省...”。这表示磁盘上记录的实际结构是问题的开放参数之一(例如,如果我们只是从目录中的单个文件中读取,因此会强制执行非顺序读取),并且 TeraByte 大小的存储也很可能由花哨的 RAID 支持,在这种情况下,通常会大大改善寻道延迟,同时保持关注。
我坚持我的建议,即两遍方法可能比每条记录完全散列的方法更有效,但我希望我强调了可能性和好处的单程方法。与许多面试问题一样,当前情况的几个特征没有明确说明;与其说是看到申请人提供绝对正确的答案(尽管有些答案可能完全错误!),不如说是为了深入了解他/她的思维过程以及识别选项和决策点的能力。