sidebar 隐藏/显示
2007年08月11日

分布式词频统计 - []

一个规模庞大的多语言语料库,已经经过预处理,分成了12个文件,每个文件存放在一台服务器中。每个文件中包含800亿个单词,每个单词占一行,平均每个单词40字节。假设服务器都已经联网,每台服务器有双CPU和4G的内存,4×400GB的硬盘,换句话说,每台服务器就是一个高配置的PC机。请设计一个方案,找出出现频率最高的一百万个单词。

这个问题基本上可能有两种思路。第一种需要先在每台服务器,完成对单词词频的统计,进行排序,然后每两台服务器把词频统计结构进行合并,12个服务器合并到6个,然后3个,然后2个,直到所有的结果合并到一台服务器中我们就可以找出这一百万个高频词了。由于单词在服务器之间的分布可能不均匀,即使一个单词在所有的服务器中出现频率都不高,合在一起仍有可能有较高的频率,此算法几乎没有优化的余地。

举个例子,单词A只出现在一台机器上,出现了10万次。单词B在每台机器上都出现1万次。从每台服务器看来,A是高频词,而B不是,但总体来说则可能正相反。每次合并统计结果时,本地机器中所有词频高于第一百万个高频词的词频的1/N的单词都要通过网络传输到另一台机器中。这里N是当下包含词频统计的服务器的数目。总体来说这个方法效率比较低。

另一个方案要每台服务器负责一部分单词的词频统计,之后再采用分布式的分割算法找出前一百万个高频词。个人觉得这个算法更加可行,下面详细描述:

  1. 定义一个哈希函数将每个单词映射为1到12之间的一个数字,从而把单词均匀分割为12组。这样我们可以确定哪台服务器负责维护这个单词的词频。
  2. 每台服务器建立12个分离的结构,用于统计每一组单词的词频。可以用哈希表也可以用前缀树。
  3. 每台服务器中统计词频的过程很简单,关键的问题在于当内存不足的时候如何处理。这里要作一点区分,对于第N个服务器中:
    1. 除第N组单词以外词频信息占用内存最多的是第X组单词,我们可以直接将现有的统计结果发送到第X个服务器中。第X个服务器会将它自身的第X组单词的统计结果和接收到的统计结果进行合并。
    2. 第N组单词的统计信息如果占用了过多的内存也会导致整个过程变慢。因而,当它占用内存超过比如说2G时,我们可以将当前的统计信息写入硬盘,这样可以腾出更多的内存。只要我们保证在磁盘中和在内存里统计信息按相同的顺序排列,我们可以非常高效的将两组统计信息合并。不如说按照字典序(使用前缀树)或者按照哈希值加字典序(使用哈希表)
  4. 当每台服务器处理完本地的语料库後,将所有的不是自己负责的单词的统计信息发送到对应的服务器中,并进行合并。这样每个单词的词频统计信息都唯一的出现在一台服务器中。
  5. 采用和《中间值》类似的分布式算法,我们可以轻易地将频率最高的一百万单词和剩下的单词分开来。注意这里我们并没有为这些单词排序。


记N为每台计算机上的单词数,M为不同的单词数。

每台服务器进行词频统计的计算复杂度为 O(N)。
总通讯量为O(M)。
寻找分割点时服务器的总计算量为O(M)
寻找分割点时协调人的额外计算量O(log M)





评论

  • 这正是我说的第一种方法,他的问题是每个服务器上词频大于c/12的数量远远超过100万个(假设词频正态分布),造成通讯量巨大,且合并结果用的服务器将成为计算和通信的瓶颈。

    deanjiang () 发表于 2008-04-02 17:46:53  [回复]
  • 上面说的办法适用于真实的分布。
    如果刻意制造人为的词频分布,可以使用下面办法来保证:

    用前面介绍的方法得到100万之后,记下第100万的词频c.
    然后把每个服务器负荷出现次数>c/12的单词全部统计出来,再合并到总结果中,重复前面的办法修正遗漏的服务器。

    这样就彻底保证最后的合并结果后,一定包含所要的100万单词。


    当然这只有在总单词数大于100万好几倍时,有价值,否则完全可以全部单词合并,不必只取前100万或120万了。

    freeman (http://FUJIAN) 发表于 2008-02-23 13:32:00  [回复]
  • 很好办。
    每个服务器取出最高频120万后合并。
    然后把合并结果发给每个服务器,根据这个合并结果,调出原先原来被本服务器淘汰掉的单词(因为对本服务器它不是高频词),调回这些修正数据,追加到总前面的合并结果中,最后得到就是这120万个单词完整的词频数据。

    最后再排序截取100万即可。

    freeman (http://FUJIAN) 发表于 2008-02-23 13:06:18  [回复]

发表评论

 姓名:
 E-mail:
 地址: