map reduce,从一行计算一个参数,然后计算第二个参数

enxuqcxy  于 2021-06-02  发布在  Hadoop
关注(0)|答案(1)|浏览(461)

假设我有一个日志文件,里面有很多行:
“a,b,c”,虽然这些变量可以有任何值,但这些值的重复出现确实会发生,这就是本分析的内容。

第一步

Map所有的“c”url,其中“a”等于一个特定的域,例如“stackoverflow.com”,而c等于url,例如“stackoverflow.com/test/user/”,我编写了一个正则表达式来实现这一点。

第二步

计数(减少)所有计数的c的(网址),这样我就有了一个名单,总计数为每个网址。这个很好用。
第三步
(尚未实施和本次考试的主题)
查找步骤2中每个已计数url的所有b(浏览器名称)。返回一个关系列表,例如dictionary adt或json,如下所示:

[
   {
    "url":Stackoverflow.com/login, 
    "count": 200.654, 
    "browsers":[
      Firefox 33, 
      IE 7, 
      Opera
    ]
   },
   {..},
   {..}
 ],

我在考虑在我的代码中引入一个组合器(见下文),或者是链式的东西。但这里真正的问题是如何优化我的工作流程,使我只需在所有日志行中运行一次?

mapreduce作业(mrjob)

FULL_URL_WHERE_DOMAIN_EQUALS = mySuperCoolRegex

class MRReferralAnalysis(MRJob):

    def mapper(self, _, line):

        for group in FULL_URL_WHERE_DOMAIN_EQUALS.findall(line):
            yield (group, 1)

    def reducer(self, itemOfInterest, counts):
        yield (sum(counts), itemOfInterest)

    def steps(self):
        return [
            MRStep( mapper=self.mapper,
                    reducer=self.reducer)
        ]

if __name__ == '__main__':
    MRReferralAnalysis.run()

总结

这就是我想要的伪代码:

LOGS_1 -> MAPREDUCE OVER SOME_CRITERIA -> LIST_1

FOR EVERY ITEM IN LIST_1:
    LOGS_1 -> MAPREDUCE OVER ITEM_CRITERIA -> LIST_2
6kkfgxo0

6kkfgxo01#

这是一个非mrjob、非mapreduce的解决方案。它只在日志文件中运行一次。它和你的输出规格有点不同, browsers 是(browser,count)元组的列表,它生成无序的字典。 collections.OrderedDict 可以被替代。
假定文件如下所示

domain,browser,url
wonderful.edu,IE,wonderful.edu/pix
odd.org,Firefox,odd.org/login
wonderful.edu,Opera,wonderful.edu/pix

读取文件并按域、url、浏览器进行排序,以便与一起使用 itertools.groupby ```
import collections, itertools, operator
with open('fake.log') as f:
lines = [tuple(line.strip().split(',')) for line in f]

lines.sort(key = operator.itemgetter(0,2,1))

一些有用的callable

domain = operator.itemgetter(0)
browser = operator.itemgetter(1)
url = operator.itemgetter(2)

使用 `collections.Counter` 计算每个唯一url的浏览器数。url计数是所有浏览器计数的总和。

results = list()
FULL_URL_WHERE_DOMAIN_EQUALS = re.compile('.*.(edu|org|com)')
for d, group in itertools.groupby(lines, domain):
# this outer loop only needed if filtering by domain
if not FULL_URL_WHERE_DOMAIN_EQUALS.match(d):
print d
continue
for u, group2 in itertools.groupby(group, url):
browsers = itertools.imap(browser, group2)
browser_count = collections.Counter(browsers)
results.append({'url' : u,
'count' : sum(browser_count.viewvalues()),
'browsers' : browser_count.items()}
)

生产

[{'browsers': [('Chrome', 2), ('IE', 4), ('Opera', 7), ('Firefox', 6)],
'count': 19,
'url': 'odd.org/foo'},
{...},
{...}]

相关问题