我正在开发著名的 WordCount 程序的一个稍微改进的版本,它应该输出该单词在书中所占的百分比。例如:
...
war 0.00002332423%
peace 0.0034234324%
...
基本上,我需要计算所有单词的数量,计算每个单词的出现次数,然后将这组值除以总数。所以至少应该有两个工作:
作业1
- 获取
input
目录并生成两个输出目录:output1
和output2
- 映射器:将
(word, 1)
对写入到output1
,将对("total_count", 1)
写入output2
- Reducer:将具有相同键的对求和,以在
output1
中生成(word, n)
,计算总计数以生成("total_count", N )
在output2
作业2
- 将
output1
和output2
作为输入文件夹,将结果写入output3
- Mapper:不做任何事情,只是写下它得到的相同对
- Reducer:获取单个值并将其除以
total_count
,将结果写入output3
我的问题:
我想避免两次查看原始输入,这就是为什么我尝试计算 Job1 中的字数和总计数。但我不明白如何避免混淆一个输出中的结果。我尝试过使用 MultipleOutputs,但在这种情况下,映射器的结果不会进入 reducer 。
Job2 需要多个输入,而且它需要先读取
output2
,因为没有总计数,从output1
读取结果是没有用的。我觉得这是使用 MapReduce 的错误方式(我们不应该使用任何类型的同步),但没有看到正确的方式。Job2 中的映射器没有做任何有用的事情,只会浪费处理器时间。
最佳答案
关于使用单个作业的想法:
total_count
可以从第一个作业的映射阶段计算出来。实际上,它已经被计为MAP_OUTPUT_RECORDS
。这是所有映射输出 (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();
关于java - Hadoop 的单词百分比程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22357561/