【问题标题】:Most frequent words in a terabyte of data1 TB 数据中出现频率最高的词
【发布时间】:2012-09-21 06:41:32
【问题描述】:

我遇到了一个问题,我们必须在 TB 的文件或字符串中找到说最频繁的 10 个单词。

我能想到的一个解决方案是使用哈希表(单词、计数)和最大堆。但是,如果单词是唯一的,则拟合所有单词可能会导致问题。 我想到了另一种使用 Map-Reduce 的解决方案,方法是将块拆分到不同的节点上。 另一种解决方案是为所有单词构建一个 Trie,并在我们扫描文件或字符串时更新每个单词的计数。

以上哪一项是更好的解决方案?我认为第一个解决方案非常幼稚。

【问题讨论】:

  • 您是否总是需要最佳答案,或者您对某种启发式算法感兴趣?
  • 其实我正在寻找一种尽可能降低时间和空间复杂度的最佳算法。并考虑到无法在内存中读取整个数据。
  • 所提到的问题有很多 - 所以有各种各样的答案,包括:(1)如果是面试,如何回答的扩展讨论,(2)很好的问题分析,(3 ) map-reduce 解决方案,(4) 映射解决方案 (5) 基于 SQL 的解决方案,等等。

标签: algorithm bigdata


【解决方案1】:

将可用内存分成两半。将一个用作 4 位 counting Bloom filter,另一半用作具有计数的固定大小哈希表。计数布隆过滤器的作用是过滤掉很少出现的单词,内存效率很高。

对照最初为空的 Bloom 过滤器检查 1 TB 的单词;如果一个词已经存在并且所有的桶都设置为最大值 15(这可能部分或全部是误报),通过它。如果不是,请添加它。

通过的单词被计算在内;对于大多数单词来说,这是每次看到它们的前 15 次。一小部分将更快地开始计算,从而为您的结果带来每个单词多达 15 次出现的潜在不准确性。这是 Bloom 过滤器的限制。

当第一遍结束时,如果需要,您可以通过第二遍来纠正不准确之处。释放 Bloom 过滤器,也释放所有不在第十个最频繁单词后面 15 次出现的计数。再次检查输入,这一次准确地计算单词(使用单独的哈希表),但忽略从第一次传递中未保留为近似获胜者的单词。

备注

理论上,第一遍中使用的哈希表可能会因输入的某些统计分布(例如,每个单词正好 16 次)或 RAM 极其有限而溢出。由您来计算或尝试这是否真的会发生在您身上。

还请注意,桶宽度(上述描述中的 4 位)只是构造的一个参数。非计数 Bloom 过滤器(桶宽度为 1)可以很好地过滤掉大多数独特的词,但不会过滤掉其他很少出现的词。更宽的桶大小将更容易在单词之间产生串扰(因为桶会更少),并且它还会降低第一次通过后保证的准确度水平(在 4 位的情况下出现 15 次)。但在某些时候,这些缺点在数量上是微不足道的,而我认为更积极的过滤效果对于将哈希表保持在亚 GB 大小和非重复自然语言数据中是完全关键的。

至于布隆过滤器本身的数量级内存需求; these people 正在以低于 100 MB 的方式工作,并且具有更具挑战性的应用程序(“完整”n-gram 统计,而不是阈值 1-gram 统计)。

【讨论】:

  • 我了解了整个概念。但是你能简单解释一下第2段吗?我不清楚为什么我们需要检查桶中的最大值是否为15。以及为什么只需要 4 位计数布隆过滤器。
  • @Askhay - 我添加了一些讨论。如果我确定您的 1 TB 是英文散文,我会冒昧地建议 10 位计数。但是,桶太宽可能会导致答案中未提及的问题 - 如果您将桶设置为 40 位宽,那么任何文字都不会通过。
【解决方案2】:

使用合并排序按字母顺序对 TB 文件进行排序。在初始阶段,使用所有可用的物理 RAM 使用快速排序来对长时间运行的单词进行预排序。

这样做时,只用一个这样的单词和一个计数来表示一个连续的相同单词序列。 (也就是说,您在合并期间添加计数。)

然后重新使用文件,再次使用带有快速排序预排序的合并排序,但这次是按计数而不是按字母顺序。

这比我的其他答案更慢但更容易实现。

【讨论】:

    【解决方案3】:

    我能想到的最好的:

    1. 将数据拆分为可以存储在内存中的部分。
    2. 对于每个部分,获得N 最常用词,您将获得N * partsNumber 词。
    3. 再次读取所有数据,计算之前获得的单词数。

    它不会总是给你正确的答案,但它会在固定的内存和线性时间内工作。

    【讨论】:

    • 是的,这似乎是一个更好的解决方案。时间 O(n) 和空间 N*partsNumber。
    • 就像你说的,它并不总是给你正确的答案,所以我看不出它是一个正确的算法
    • @Yarneo “正确的算法”是什么意思。我认为算法,如果它有 TB 的内存和多年的时间,它会给出一些好的答案(大多数情况下最好,有时接近最好)比总是给出最好答案的算法要好。
    • 我很抱歉这个“头疼”的答案,你是对的。我的意思是,至少对于这个问题,这是一个经典的 map-reduce 问题,您可以获得具有良好时间复杂度的精确答案。
    • @Yarneo 你是 100% 正确的如果有快速和正确的(最佳答案)算法。我不知道这样的算法,但你说有一个所以我的答案不好
    【解决方案4】:

    为什么你认为建造 Trie 结构不是最好的决定?用计数器标记所有子节点,就是这样!最大内存复杂度为 O(26 *longest_word_length),时间复杂度为 O(n),还不错吧?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-28
      • 1970-01-01
      • 2019-05-02
      • 1970-01-01
      • 2013-12-20
      • 2017-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多