我正在研究一个着名的WordCount程序的略微改进版本,该程序应该输出该单词所占的百分比。例如:
...
war 0.00002332423%
peace 0.0034234324%
...
基本上,我需要计算所有单词,计算每个单词的出现次数,将这组值除以总计数。所以应该至少有两个工作:
作业1
input
目录并生成两个输出目录:output1
和output2
(word, 1)
写入output1
,将对("total_count", 1)
写入output2
(word, n)
中生成output1
,计算("total_count", N)
中output2
的总计数作业2
output1
和output2
作为输入文件夹,将结果写入output3
total_count
,将结果写入output3
我的问题:
我想避免两次原始输入,这就是为什么我要在Job1中计算字数和总数。但我不明白如何避免在一个输出中混淆结果。我曾尝试使用MultipleOutputs
,但在这种情况下,映射器的结果不会进入reducer。
Job2需要多个输入,而且需要首先阅读output2
,因为没有总计数,从output1
读取结果是没用的。我觉得这是使用MapReduce的错误方法(我们不应该使用任何类型的同步)但看不到正确的方法。
Job2中的Mapper没有任何用处,只会浪费处理器时间。
答案 0 :(得分:2)
只想到使用一份工作:
total_count
可以从第一份工作的地图阶段计算出来。实际上,它已被计为MAP_OUTPUT_RECORDS
。这是所有地图输出(key, value)
对的总和。因此,如果您总是将1作为值,则此总和就是您想要的,即文档中的单词总数(重复)。
现在,我不知道你是否可以在减速器的配置中得到这个计数器。然后,您可以为每个单词输出(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();
答案 1 :(得分:0)
非优化方法是创建一个特殊单词(例如" 00000")并使用它来计算所有单词。 Mapper 1会为它遇到的每个单词写出(单词,1)和(" 00000",1)。然后,Reducer 1将计算所有单词以及计算总数(" 00000"的计数)。
下一个作业将有一个直通映射器,减速器将计算百分比。这里的诀窍是(1)有一个减速器和(2)选择你的" 00000"单词,以便它在所有其他单词之前排序。通过这种方式,总数首先传递给Reducer 2,并且对于所有后续的字数都是已知的。