我正在开发著名的WordCount程序的稍有改进的版本,该程序应输出该单词占本书的百分比。例如:

...
war 0.00002332423%
peace 0.0034234324%
...

基本上,我需要计算所有单词,计算每个单词的出现次数,然后将这组值除以总计数。因此,至少应该有两个工作:

作业1
  • 进入input目录并生成两个输出目录:output1output2
  • 映射器:将对(word, 1)对写入output1,对("total_count", 1)对写入output2
  • Reducer:将具有相同键的对加起来以在(word, n)中生成output1,计算总数以在("total_count", N)中生成output2

  • 工作2
  • output1output2作为输入文件夹,并将结果写入output3
  • Mapper:不执行任何操作,只写下获得
  • 的相同对
  • Reducer:采用单个值并将其除以total_count,将结果写入output3

  • 我的问题:
  • 我想避免两次通过原始输入,这就是为什么我试图同时计算Job1中的字数和总数。但是我不明白如何避免在一个输出中混淆结果。我尝试使用MultipleOutputs,但在这种情况下,映射器的结果不会进入reducer。
  • Job2需要多个输入,此外,它还需要首先读取output2,因为如果没有总数,从output1中读取结果是没有用的。我认为这是使用MapReduce的错误方式(我们不应使用任何类型的同步),但看不到正确的方式。
  • Job2中的
  • Mapper没有任何用处,只会浪费处理器时间。
  • 最佳答案

    只需考虑使用一个Job:
    total_count可以从第一个作业的 map 阶段计算得出。实际上,它已经被算作MAP_OUTPUT_RECORDS了。这是所有 map 输出(key, value)对的总和。因此,如果您始终将值设为1,则此总和就是您想要的,即文档中单词的总数(重复)。

    现在,我不知道您是否可以在 reducer 的配置中获得此计数器。然后,您可以为每个单词输出一对(word, wordCount/MAP_OUTPUT_RECORDS)。我认为您可以通过以下方式做到这一点:

    新API:

    context.getCounter("org.apache.hadoop.mapred.Task$Counter", "MAP_OUTPUT_RECORDS").getValue();
    

    旧API:
    reporter.getCounter("org.apache.hadoop.mapred.Task$Counter", "MAP_OUTPUT_RECORDS").getValue();
    

    08-19 20:44