快捷搜索: 王者荣耀 脱发

Mapreduce中分组排序的一些认识

今天偶然和朋友讨论了下关于Mapreduce中分组排序输出topN的问题。为了方便大家理解,特意将聊天的细节分享给大家。

业务逻辑经常会有topN的需求,通常我们对数据进行排序规则制定之后,我们并不能够按需求获得我们需要的数据,其关键原因就在于我们没有自定义分组。

自定义分组,涉及到的一个关键类为WritableComparator。自定义分组的第一步,就是要编写一个类去继承该类,然后重写其compare方法。

以下是例子:

假设我们有一组网站用户购物记录,我们需要获取用户的消费信息,按时间顺序输出每月消费金额前100的用户信息。

完成pojo类后,初学者可能会直接将pojo类作为可以,传输到mapreduce程序中,然后调用context.write方法,输出前100个值。这个时候,错误就来了。你会发现,自己输出的数据虽然是100条,但是却不是每月的top100。这是为什么呢?原因就在于分组,由于没有分组,在reducer的reduce方法中,每次输出调用迭代器输出值得时候,获取top100并不是在每个以月份划分的组中获取的。(reduce程序按照先时间排序,在消费金额排序,将所有的键值对无差别的排在了一起,后去的时候,直接选取前100个,而不会去区分是不是从每个不同的月份中分别获取了前100个数据。)。不分组的情况下,所有的pojo对象都是一个单独的key存入reducer。而分组后,reducer会按照月份为key,然后将相同月份的客户信息当做值,存在reduce方法的迭代器中。从而通过迭代,可以获取到我们需要的前100个消费者的信息。因此,解决问题的关键就在于分组规则的制定。

下面就是关键,通过自定义分组,告诉框架,按组每次获取前100,才是我们需要的最终数据。自定义分组规则,需要编写一个类,去继承WritableComparator类,然后重写其中的compare方法。此处,我们会传入参数,为自定义的pojo对象。在compare方法通过返回compareTo方法的返回值,来制定分组规则。在此处有个需要注意的地方是,由于我们需要反序列化对象到compare方法中用,必须调用父类中的一个方法来激活反序列化。设置方式为在构造器中调用super(pojo.class,true)。

自此,我们只需要最后一步,就可以完成任务了。那就是在你的mapreduce程序中,设置下你自定义的comparetor,所以在main方法中添加上这么一句:job.setGroupingComparatorClass(PojoGroupComparator.class);

搞定!希望对大家有所帮助,有什么不明白的,欢迎私信,留言!

经验分享 程序员 微信小程序 职场和发展