我试图更好地理解mrjob的例子
from mrjob.job import MRJob
class MRWordFrequencyCount(MRJob):
def mapper(self, _, line):
yield "chars", len(line)
yield "words", len(line.split())
yield "lines", 1
def reducer(self, key, values):
yield key, sum(values)
if __name__ == '__main__':
MRWordFrequencyCount.run()
我通过
运行它$ python word_count.py my_file.txt
它按预期工作但我不知道它是如何自动知道它将读取文本文件并按每行分割它。而且我不确定_
是做什么的。
根据我的理解,mapper()
为每一行生成三个键/值对是否正确?如果我想处理文件夹中的每个文件怎么办?
reducer()
会自动知道如何添加每个键的值吗?
如果我想通过map reduce运行单元测试怎么办?mapper和reducer会是什么样子?它甚至是必要的吗?
答案 0 :(得分:4)
mapper方法接收已从输入文本中解析出的键值对。 mrjob使用Hadoop流,每个输入文本被新行字符分割,然后根据使用的输入协议将每行分成键值对。这是框架为你照顾的东西,所以你不必做任何繁重的工作;你可以假设你会获得适当的关键和价值。
但是,您需要指定指定的输入文本文件类型。例如,如果键和/或值不是纯文本(如原始问题中),而是序列化的JSON,则使用JSONProtocol / JSONValueProtocol等,而不是默认的RawValueProtocol。
对于初始映射器,每行都被读入值(通过RawValueProtocol),这就是您不接收密钥的原因。使用_
只是未使用的虚拟变量的Python约定。 (但是,_
实际上是Python变量的有效名称。你可以做这样的事情a = 3; _ = 2; b = a + _
。亵渎,不是吗?)
mrjob可以输入多个输入文件。你可以做例如
$ python wordcount.py text1.txt text2.txt
如果您希望将所有文本文件作为mrjob作业的输入,则可以执行
之类的操作$ python wordcount.py inputdir/*.txt
或只是简单地
$ python wordcount.py inputdir
并且所有选定的文件都用作输入。
reducer接收的是与该键关联的所有值的键和迭代器。因此,如果您举例,则reducer方法中的变量values
是迭代器。如果要对所有值执行某些操作,则需要实际迭代所有值。在问题的具体示例中,内置函数sum
可以将迭代器作为参数,这就是为什么你可以一次性完成它。但它实际上类似于sum([value for value in values])
。
我实际上不知道如何对mrjob脚本进行单元测试。在生产运行之前,我通常只测试了一小部分测试数据。
答案 1 :(得分:2)
我对mrjob不太了解,所以我要做一些假设。首先,_表示忽略密钥(在Google搜索后验证)。其次,我认为它可以在逗号分隔的文件列表或目录上工作。接下来,此代码缺少设置可能因为这些是默认方法名称。我确定你是否将你的映射器或减速器命名为不同的东西,mrjob无法自动拾取它。
我找到了一些例子here。
答案 2 :(得分:0)
from mrjob.job import MRJob
class MRRatingCounter(MRJob):
def mapper(self, key, line):
(userID, movieID, rating, timestamp) = line.split('\t')
yield rating, 1
def reducer(self, rating, occurences):
yield rating, sum(occurences)
if __name__ == '__main__':
MRRatingCounter.run()
所以请根据以上讨论纠正我:
如果我错了,请纠正我,所以在这种情况下,键是取输入文件的值,在这种情况下,我可以在脑海中读出这样的内容:
def mapper(自我{这是对象/实例},键{输入文本文件在这种情况下是文件的名称并且正确我ml-100k / u.data,行{这是正在尝试每次从数据文件传递给mapper()。)
Udemy的另一个代码我正在尝试学习,原始问题是: MRFriendsByAge(MRJob):
def mapper(self, _, line):
(ID, name, age, numFriends) = line.split(',')
yield age, float(numFriends)
def reducer(self, age, numFriends):
total = 0
numElements = 0
for x in numFriends:
total += x
numElements += 1
yield age, total / numElements
如果名称 ==' 主要': MRFriendsByAge.run()
Found a MR job book and am trying to see if its make sense but i am still struggling