Hadoop-mapreduce案例-GroupingComparator应用-查询订单最大金额

本文详细介绍了如何通过自定义Bean、Partitioner、GroupingComparator等技术处理订单数据,旨在找出同一订单下的最大成交金额,同时提供了完整的代码实现,包括Mapper、Reducer及自定义组件的编写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

订单数据如下(订单id,   商品id,  成交金额 ): 

Order_0000001,Pdt_01,222.8
Order_0000001,Pdt_05,25.8
Order_0000002,Pdt_05,325.8
Order_0000002,Pdt_03,522.8
Order_0000002,Pdt_04,122.4
Order_0000003,Pdt_01,222.8
Order_0000003,Pdt_01,322.8

需求:
找出订单号相同的最大成交金额的订单信息,比如订单号Order_0000001的最大交易额为222.8

思路1:
在map中将订单号作为key,其他数据封装bean 输出,在reduce中对bean中的成交金额进行排序,筛选出最大的成交金额。

思路2:
我们可以再map中将订单id跟订单金额封装成一个bean作为key,null作为value输出,输入到reduce之前,这里用前面介绍的,让bean实现WritableComparable然后重写compareTo(用来排序)方法,使得不同订单号的订单先按照订单号由小到大排序,相同订单号的订单按照成交额倒排序。但是存在一个问题,此时由于bean作为key那么不一定能保证传到同一个reduce中,都不在一个reduce中了那肯定也不能去比较订单号相同的记录了,这个时候就需要自己指定自定义的Partitioner(用来分区)了来使得相同订单id的订单记录传到同一个reduce中。最后由于key不同那么传到reduce中的时候,即使是相同订单id的bean也只会一次一次传到reduce,那么还怎么取比较呢?此时就要使用自定义GroupingComparator(用来分组)了,指定只要是订单id相同的bean都看为一组,拿Order_0000001的三条记录来说(三个bean),由于会被看成一组,那么传到reduce方法中的时候,key只传第一个bean,由于我们前面相同订单id的bean是按照成交额由高到低排的,那么这个时候传进来的key就肯定是成交额最大的bean。

考虑效率方面的问题,我们实现第二种思路。

程序实现

自定义Bean

public class OrderGroupingComparator extends WritableComparator{

    //传入作为key的bean的class类型,以及指定需要让框架做反射获取实例对象
    protected OrderGroupingComparator(){
        //不能丢,注册某个bean  要不要实例化  因为拿来的时候是序列化的结果
        //实例化后才能去比
        super(InfoBean.class,true);
    }
    //相同的订单id的bean看做一组(value值作为迭代器中数据),传到reduce中的时候取第一个bean
    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        InfoBean bean1 = (InfoBean)a;
        InfoBean bean2 = (InfoBean)b;
        return bean1.getOrderId().compareTo(bean2.getOrderId());
    }
}

自定义Partitioner

public class OrderPartitioner extends Partitioner<InfoBean, NullWritable>{

    //分区方法,返回值表示分区号,与reducetask对应
    @Override
    public int getPartition(InfoBean key, NullWritable value, int numReduceTasks) {
        //使相同id的订单bean交给同一个reducetask
        //这里参照HashPartitioner来写
        return (key.getOrderId().hashCode()& Integer.MAX_VALUE) % numReduceTasks;
    }

}

自定义GroupingComparator

public class OrderGroupingComparator extends WritableComparator{

    //传入作为key的bean的class类型,以及指定需要让框架做反射获取实例对象
    protected OrderGroupingComparator(){
        //不能丢,注册某个bean  要不要实例化  因为拿来的时候是序列化的结果
        //实例化后才能去比
        super(InfoBean.class,true);
    }
    //相同的订单id的bean看做一组(value值作为迭代器中数据),传到reduce中的时候取第一个bean
    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        InfoBean bean1 = (InfoBean)a;
        InfoBean bean2 = (InfoBean)b;
        return bean1.getOrderId().compareTo(bean2.getOrderId());
    }
}

主程序

public class MaxPaymentWithOrder {
    static class MaxPaymentWithOrderMapper extends Mapper<LongWritable, Text, InfoBean, NullWritable>{
        InfoBean bean = new InfoBean();
        //读取一行数据,封装成bean作为key写出
        //传入格式Order_0000001,Pdt_01,222.8
        @Override
        protected void map(LongWritable key, Text value, Context context)
                throws IOException, InterruptedException {
            String line = value.toString();
            String[] infos = line.split(",");
            bean.setInfoBean(new Text(infos[0]), new DoubleWritable(Double.parseDouble(infos[2])));
            context.write(bean, NullWritable.get()); 
        } 
    }
    static class MaxPaymentWithOrderReducer extends Reducer<InfoBean, NullWritable, InfoBean, NullWritable>{
        //将相同id的订单看成一组传进来(使用自定义GroupingComparator实现)
        //而key只会取第一个
        @Override
        protected void reduce(InfoBean key, Iterable<NullWritable> value,Context context)
                throws IOException, InterruptedException {
            context.write(key, NullWritable.get());
        }
    }
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf);
        //jar包位置
        job.setJarByClass(MaxPaymentWithOrder.class);

        job.setMapperClass(MaxPaymentWithOrderMapper.class);
        job.setReducerClass(MaxPaymentWithOrderReducer.class);
        job.setMapOutputKeyClass(InfoBean.class);
        job.setMapOutputValueClass(NullWritable.class);
        //设置最终输出类型
        job.setOutputKeyClass(InfoBean.class);
        job.setOutputValueClass(NullWritable.class);
        //设置reducetask数量
        job.setNumReduceTasks(2);
        //指定Partitioner
        job.setPartitionerClass(OrderPartitioner.class);
        //指定GroupingComparator
        job.setGroupingComparatorClass(OrderGroupingComparator.class);
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        boolean ex = job.waitForCompletion(true);
        System.exit(ex?0:1); 
    }
}

原文:https://blog.youkuaiyun.com/qq_37334135/article/details/78255411

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值