我在接受采访时被问到这个问题,我不确定我是否给出了正确的答案,所以我想要一些见解。
问题:有一组用户和项目。在每一分钟,我都会收到一个元组列表(用户,项目),表示用户 u 消耗的项目 i 。我需要在过去一小时内找到前100个热门项目,即计算每个项目消耗的用户数量并对其进行排序。这里的诀窍是,在过去的一小时内,如果一个项目被同一个用户多次使用,则只考虑一次消费。不允许同一用户重复消费。面试官说我应该认真思考,每小时会有数百万的消费。所以,他建议我做一个map-reduce工作或者每分钟可以处理大量数据的东西。
我提出的解决方案:我说我可以维护一个消费的用户项 - 时间戳元组的列表(或者你喜欢的矩阵),就像有时间一样 - 窗口移位。类似的东西:
在每分钟,当我收到此分钟的用户项目消耗流时,我首先使用当前时间戳创建map-reduce作业以更新时间窗口矩阵。这个map-reduce作业可以由两个映射器完成(一个用于流,另一个用于时间窗口列表),reducer将简单地获得每对的最大值。我所做的伪代码:
mapTimeWindow(line):
user, item, timestamp = line.split(" ")
context.write(key=(user,item), value=timestamp)
mapStream(line):
user, item = line.split(" ")
context.write(key=(user,item), value=now())
reducer(key, list):
context.write(key=(user,item), value=max(list))
接下来,我还通过计算每个用户在该列表中出现的时间来执行map-reduce来计算流行度。我的地图读取更新的时间窗口列表和写入项目1.减速器计算每个项目的列表总和。由于我存储了所有时间戳,因此我验证消耗是否在过去一小时内。另一个map-reduce伪代码:
mapPopularity(line):
user, item, timestamp = line.split(" ")
if now()-60>timestamp:
return
context.write(key=item, value=1) # no repetition
reducerPopularity(key, list):
context.write(key=item, value=sum(list))
稍后我们可以执行另一个map-reduce来读取第二个作业的结果并计算top100最大的项目。像this那样做的事情。
我的问题:这个解决方案对于我的采访是否可以接受?它包含三个map-reduce来解决问题。但是,在我看来,每分钟都要执行很多。由于它需要每分钟更新一次,因此不能持续更长时间。我的意思是,我付出了很多努力,但面试官并没有给我反馈,如果它是对的。我想知道:是否可以加快速度?或者是否有可能以另一种方式处理这个问题? (也许不是map-reduce)