我正在尝试理解Python中的Hadoop字数计算示例 http://www.michael-noll.com/tutorials/writing-an-hadoop-mapreduce-program-in-python/
作者从初始版本的mapper和reducer开始。这是reducer(我为了简洁而删除了一些注释)
#!/usr/bin/env python
from operator import itemgetter
import sys
current_word = None
current_count = 0
word = None
# input comes from STDIN
for line in sys.stdin:
line = line.strip()
word, count = line.split('\t', 1)
try:
count = int(count)
except ValueError:
continue
if current_word == word:
current_count += count
else:
if current_word:
# write result to STDOUT
print '%s\t%s' % (current_word, current_count)
current_count = count
current_word = word
# do not forget to output the last word if needed!
if current_word == word:
print '%s\t%s' % (current_word, current_count)
作者用以下方式测试该程序:
echo "foo foo quux labs foo bar quux" | /home/hduser/mapper.py | sort -k1,1 | /home/hduser/reducer.py
因此,reducer的编写就好像reducer作业的输入数据一样:
aa 1
aa 1
bb 1
cc 1
cc 1
cc 1
我对reducer的初步了解是,给定reducer的输入数据将包含一个唯一键。因此,在前面的示例中,将需要3个减速器作业。我的理解不正确吗?
然后作者提出了mapper和reducer的改进版本。这是减速器:
#!/usr/bin/env python
"""A more advanced Reducer, using Python iterators and generators."""
from itertools import groupby
from operator import itemgetter
import sys
def read_mapper_output(file, separator='\t'):
for line in file:
yield line.rstrip().split(separator, 1)
def main(separator='\t'):
# input comes from STDIN (standard input)
data = read_mapper_output(sys.stdin, separator=separator)
for current_word, group in groupby(data, itemgetter(0)):
try:
total_count = sum(int(count) for current_word, count in group)
print "%s%s%d" % (current_word, separator, total_count)
except ValueError:
# count was not a number, so silently discard this item
pass
if __name__ == "__main__":
main()
作者添加了以下警告:
注意:以下Map和Reduce脚本只能“正确”工作 在Hadoop上下文中运行时,即在a中使用Mapper和Reducer MapReduce工作。这意味着运行天真的测试命令“cat 数据| ./mapper.py | sort -k1,1 | ./reducer.py“不起作用 正确的,因为某些功能是故意的 外包给Hadoop。
我不明白为什么天真的测试命令不适用于新版本。我认为使用sort -k1,1
会为两个版本的reducer产生相同的输入。我错过了什么?
答案 0 :(得分:0)
关于你的第一个问题:“我对减速器的初步了解是给定减速器的输入数据将包含一个唯一的密钥。因此在前面的例子中,需要3个减速器作业。我的理解是不正确的吗?”< / p>
MapReduce抽象和Hadoop的抽象实现之间存在差异。在抽象中,reducer与唯一键相关联。另一方面,Hadoop实现为同一个reducer分配了几个键(以避免关闭进程和启动新进程的成本)。特别是,在Hadoop流式传输中,reducer接收与一定数量的键相对应的键值对(可以是零,一个或多个键),但是您可以保证与某个键相关联的键值对将是彼此连续相遇。
例如,让我们用输入“foo foo quux labs foo bar quux”的单词计数示例。然后可能是减速器接收输入“bar 1 \ nfoo 1 \ nfoo 1 \ nfoo1”而另一个减速器接收“labs 1 \ nquux 1 \ nquux 1”。运行的实际reducer进程数由您使用选项mapred.reduce.tasks决定。例如,你可以使用2个减速器
$ bin/hadoop jar contrib/streaming/hadoop-*streaming*.jar -D mapred.reduce.tasks=2 -mapper ....
关于你的第二个问题,我同意你sort -k1,1
会做的伎俩,所以我也没有看到问题。