问题描述
我一直在使用 MapReduce,对它仍然很陌生,并且想知道我是否可以就我无法回答的问题获得一些帮助: 我有一个包含日期和计数的 txt 文件,并希望根据它们各自的计数按升序对日期进行排序。文本文件如下所示:
我环顾四周,发现了一些这样的代码:
import re
从 mrjob.job 导入 MRJob 从 mrjob.step 导入 MRStep
WORD_RE = re.compile(r"[\w']+")
类 MRWordFrequencyCount(MRJob):
def steps(self):
return [
MRStep(
mapper=self.mapper_extract_words,combiner=self.combine_word_counts,reducer=self.reducer_sum_word_counts
),MRStep(
reducer=self.reduce_sort_counts
)
]
def mapper_extract_words(self,_,line):
for word in WORD_RE.findall(line):
yield word.lower(),1
def combine_word_counts(self,word,counts):
yield word,sum(counts)
def reducer_sum_word_counts(self,key,values):
yield None,(sum(values),key)
def reduce_sort_counts(self,word_counts):
for count,key in sorted(word_counts,reverse=True):
yield ('%020d' % int(count),key)
但这似乎太复杂了,因为正如您从postedDates txt 文件中看到的那样,我已经有了密钥及其各自的计数。那么我是否只需要添加第二步,它只是一个使用“sorted(counts)”对键和值列表进行排序的 reducer 函数?
对您的时间表示亲切的问候。
解决方法
您是对的,鉴于您的特定设置,当然可以使用单个 MapReduce 执行您的任务。
您可以跳过示例中的初始步骤,因为您已经有了每个日期(键)的计数。您只需执行第二步,将这些对组合成元组并根据 count
和 date
按升序计数
import datetime
from mrjob.job import MRJob
class MRDateFrequencyCount(MRJob):
def mapper(self,_,line):
date,count = line.split(' ')
yield None,(int(count),date)
def reducer(self,dates):
for count,date in sorted(dates,key=lambda x: (x[0],datetime.datetime.strptime(x[1],'"%Y-%m-%d"'))):
yield date,count
if __name__ == '__main__':
MRDateFrequencyCount.run()
产生输出:
"\"2006-11-01\"" 1
"\"2006-12-21\"" 1
"\"2006-12-11\"" 2
"\"2007-03-12\"" 3
按降序计数
import datetime
from mrjob.job import MRJob
class MRDateFrequencyCount(MRJob):
def mapper(self,key=lambda x: (-x[0],count
if __name__ == '__main__':
MRDateFrequencyCount.run()
产生输出:
"\"2007-03-12\"" 3
"\"2006-12-11\"" 2
"\"2006-11-01\"" 1
"\"2006-12-21\"" 1
注意:如果图像中数据的格式与我在下面测试的文本中显示的格式不同,则您需要更改 strptime
格式字符串 '"%Y-%m-%d"'
.
两个 MRJob 都在没有配置的情况下运行,并在包含以下文本的文本文档上运行:
"2006-12-21" 1
"2007-03-12" 3
"2006-11-01" 1
"2006-12-11" 2
当然,如果您想更改哪个列(计数或日期)排在第一或第二,您可以在任一减速器中更改 yeild
。
您还可以使用字符串格式来去除数据集中日期周围的 "
。