我从Hadoop教程中得到了这个。它是一个reducer,基本上从stdin接收(word,count)对并对它们求和。
def read_mapper_output(file, separator='\t'):
for line in file:
yield line.rstrip().split(separator, 1)
def main(separator='\t'):
data = read_mapper_output(sys.stdin, separator=separator)
for current_word, group in groupby(data, itemgetter(0)):
try:
total_uppercount = sum(int(count) for current_word, count in group)
print "%s%s%d" % (current_word, separator, total_count)
except ValueError:
pass
现在,我希望能够接受元组(word,count1,count2),但这个groupby
和sum(int(count for current_word, count in group)
业务对我来说完全难以理解。我如何修改这个块,以便它基本上继续做它现在做的事情,但是有第二个计数器值?
即输入是(word,count1,count2),输出是(word,count1,count2)。
编辑1:
from itertools import groupby, izip
from operator import itemgetter
import sys
def read_mapper_output(file, separator='\t'):
for line in file:
yield line.rstrip().split(separator, 2)
def main(separator='\t'):
data = read_mapper_output(sys.stdin, separator=separator)
for current_word, group in groupby(data, itemgetter(0)):
try:
counts_a, counts_b = izip((int(count_a), int(count_b)) for current_word, count_a, count_b in group)
t1, t2 = sum(counts_a), sum(counts_b)
print "%s%s%d%s%d" % (current_word, separator, t1, separator, t2)
except ValueError:
pass
这是一个Hadoop作业,所以输出如下:
11/11/23 18:44:21 INFO streaming.StreamJob: map 100% reduce 0%
11/11/23 18:44:30 INFO streaming.StreamJob: map 100% reduce 17%
11/11/23 18:44:33 INFO streaming.StreamJob: map 100% reduce 2%
11/11/23 18:44:42 INFO streaming.StreamJob: map 100% reduce 12%
11/11/23 18:44:45 INFO streaming.StreamJob: map 100% reduce 0%
11/11/23 18:44:51 INFO streaming.StreamJob: map 100% reduce 3%
11/11/23 18:44:54 INFO streaming.StreamJob: map 100% reduce 7%
11/11/23 18:44:57 INFO streaming.StreamJob: map 100% reduce 0%
11/11/23 18:45:05 INFO streaming.StreamJob: map 100% reduce 2%
11/11/23 18:45:06 INFO streaming.StreamJob: map 100% reduce 8%
11/11/23 18:45:08 INFO streaming.StreamJob: map 100% reduce 7%
11/11/23 18:45:09 INFO streaming.StreamJob: map 100% reduce 3%
11/11/23 18:45:12 INFO streaming.StreamJob: map 100% reduce 100%
...
11/11/23 18:45:12 ERROR streaming.StreamJob: Job not Successful!
来自日志:
java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 1
at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:311)
at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:545)
at org.apache.hadoop.streaming.PipeReducer.close(PipeReducer.java:137)
at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:473)
at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:411)
at org.apache.hadoop.mapred.Child.main(Child.java:170)
java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 1
at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:311)
at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:545)
at org.apache.hadoop.streaming.PipeReducer.close(PipeReducer.java:137)
at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:473)
at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:411)
at org.apache.hadoop.mapred.Child.main(Child.java:170)
Shuffle Error: Exceeded MAX_FAILED_UNIQUE_FETCHES; bailing-out.
答案 0 :(得分:2)
GROUPBY
这是groupby
模块中的itertools
函数,记录为here。 data
“按”将itemgetter(0)
(itemgetter
类的operator
类的实例,记录为here)应用于每个元素的结果“按”分组“ 。它返回成对的(关键结果,iterator-over-elements-with-key)。因此,每次循环时,current_word
都是一串data
行共有的“单词”(索引为0,即第一项,由itemgetter
提取) ,group
是以data
开头的word
行的迭代器。如代码文档中所述,文件的每一行都有两个单词:实际的“单词”和计数(用于解释为数字的文本)
sum(current_word的int(count),group中的count)
意味着它所说的:count
的整数值之和,对于每个current_word
,count
)对中的group
group
。如上所述,每个data
是来自current_word
的一组行。因此,我们采用以count
开头的所有行,将其字符串groupby
值转换为整数,然后将它们相加。
如何修改此块,以便它基本上继续执行它现在所做的操作,但是具有第二个计数器值?即输入是(word,count1,count2),输出是(word,count1,count2)。
那么,您希望每个计数代表什么,以及您希望数据来自何处?
我将采取我认为最简单的解释:您将修改数据文件以在每一行上有三个项目,并且您将获得总和分别来自每列数字。
sum
将是相同的,因为我们仍然以相同的方式对我们获得的行进行分组,并且我们仍然根据“单词”对它们进行分组。
group
部分需要计算两个值:第一列数字的总和和第二列数字的总和。
当我们迭代current_word, group_a, group_b
时,我们将获得三个值的集合,因此我们要将它们解压缩为三个值:例如itertools
。对于其中的每一个,我们希望将整数转换应用于每行上的两个数字。这给了我们一系列数字序列;如果我们想要添加所有第一个数字和所有第二个数字,那么我们应该制作一对数字序列。为此,我们可以使用另一个名为izip
的{{1}}函数。然后我们可以将它们分别相加,通过将它们再次打包成两个独立的数字序列变量,并对它们求和。
因此:
counts_a, counts_b = izip(
(int(count_a), int(count_b)) for current_word, count_a, count_b in group
)
total_a, total_b = sum(counts_a), sum(counts_b)
或者我们可以通过再次执行相同的操作(x中的y代表y)来制作一对计数:
totals = (
sum(counts)
for counts in izip(
(int(count_a), int(count_b)) for current_word, count_a, count_b in group
)
)
虽然在print语句中使用该结果会有点棘手:)
答案 1 :(得分:0)
from collections import defaultdict
def main(separator='\t'):
data = read_mapper_output(sys.stdin, separator=separator)
counts = defaultdict(lambda: [0, 0])
for word, (count1, count2) in data:
values = counts[word]
values[0] += count1
values[1] += count2
for word, (count1, count2) in counts.iteritems():
print('{0}\t{1}\t{2}'.format(word, count1, count2))