|NO.Z.00039|——————————|BigDataEnd|——|Hadoop&MapReduce.V12|——|Hadoop.v12|shuffle机制详解之GroupingComparator分组|

一、分区排序(默认的分区规则,区内有序)
~~~     分区排序(默认的分区规则,区内有序)
~~~     [shuffle机制详解之GroupingComparator分组]     
### --- GroupingComparator

~~~     GroupingComparator是mapreduce当中reduce端的一个功能组件,
~~~     主要的作用是决定哪些数据作为一组,调用一次reduce的逻辑,默认是每个不同的key,
~~~     作为多个不同的组,每个组调用一次reduce逻辑,
~~~     我们可以自定义GroupingComparator实现不同的key作为同一个组,调用一次reduce逻辑。
二、需求:原始数据:需要求出每一个订单中成交金额最大的一笔交易。
订单id 商品id 成交金额
Order_0000001  Pdt_01 222.8
Order_0000001  Pdt_05 25.8
Order_0000002  Pdt_03 522.8
Order_0000002  Pdt_04 122.4
Order_0000002  Pdt_05 722.4
Order_0000003  Pdt_01 232.8
### --- 实现思路

~~~     # Mapper
~~~     读取一行文本数据,切分出每个字段;
~~~     订单id和金额封装为一个Bean对象,Bean对象的排序规则指定为先按照订单Id排序,
~~~     订单Id相等再按照金额降序排;
~~~     map()方法输出kv;key-->bean对象,value-->NullWritable.get();Shuffle
~~~     指定分区器,保证相同订单id的数据去往同个分区(自定义分区器)
~~~     指定GroupingComparator,分组规则指定只要订单Id相等则认为属于同一组;
~~~     # Reduce
~~~     每个reduce()方法写出一组key的第一个
三、编程代码
### --- 编程代码

~~~     # OrderBean
~~~     OrderBean定义两个字段,一个字段是orderId,第二个字段是金额(注意金额一定要使用
~~~     Double或者DoubleWritable类型,否则没法按照金额顺序排序)
~~~     排序规则指定为先按照订单Id排序,订单Id相等再按照金额降序排!!
### --- 创建项目:group
### --- WritableComparable

package com.yanqi.mr.group;

import org.apache.hadoop.io.WritableComparable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class OrderBean implements WritableComparable<OrderBean> {

    private String orderId;//订单id
    private Double price;//金额


    public OrderBean(String orderId, Double price) {
        this.orderId = orderId;
        this.price = price;
    }

    public OrderBean() {
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    //指定排序规则,先按照订单id比较再按照金额比较,按照金额降序排
    @Override
    public int compareTo(OrderBean o) {
//        int res = this.orderId.compareTo(o.getOrderId()); //0 1 -1
//        if (res == 0) {
//            //订单id相同,比较金额
//            res = - this.price.compareTo(o.getPrice());
//
//        }



        int res =  - this.price.compareTo(o.getPrice());
        System.out.println(res);
        return res;
    }

    //序列化
    @Override
    public void write(DataOutput out) throws IOException {

        out.writeUTF(orderId);
        out.writeDouble(price);
    }

    //反序列化
    @Override
    public void readFields(DataInput in) throws IOException {
        this.orderId = in.readUTF();
        this.price = in.readDouble();
    }

    //重写toString()

    @Override
    public String toString() {
        return orderId + '\t' +
                price
                ;
    }
}
### --- 自定义分区器
### --- 保证ID相同的订单去往同个分区最终去往同一个Reducepackage com.yanqi.mr.group;

import org.apache.avro.Schema;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class GroupReducer extends Reducer<OrderBean, NullWritable, OrderBean, NullWritable> {

    //key:reduce方法的key注意是一组相同key的kv的第一个key作为传入reduce方法的key,因为我们已经指定了排序的规则
    //按照金额降序排列,则第一个key就是金额最大的交易数据
    //value:一组相同key的kv对中v的集合
    //对于如何判断key是否相同,自定义对象是需要我们指定一个规则,这个规则通过Groupingcomaprator来指定
    @Override
    protected void reduce(OrderBean key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {
        //直接输出key就是金额最大的交易
        context.write(key, NullWritable.get());
    }
}
### --- 自定义GroupingComparator
### --- 保证id相同的订单进入一个分组中,进入分组的数据已经是按照金额降序排序。reduce()方法取出第一个即是金额最高的交易

package com.yanqi.mr.group;

import com.sun.corba.se.impl.orb.ParserTable;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;

public class CustomGroupingComparator extends WritableComparator {

    public CustomGroupingComparator() {
        super(OrderBean.class, true); //注册自定义的GroupingComparator接受OrderBean对象
    }

    //重写其中的compare方法,通过这个方法来让mr接受orderid相等则两个对象相等的规则,key相等

    @Override
    public int compare(WritableComparable a, WritableComparable b) { //a 和b是orderbean的对象
        //比较两个对象的orderid
        final OrderBean o1 = (OrderBean) a;
        final OrderBean o2 = (OrderBean) b;
        final int i = o1.getOrderId().compareTo(o2.getOrderId());
        return i; // 0 1 -1
    }
}
### --- Mapper

package com.yanqi.mr.group;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

public class GroupMapper extends Mapper<LongWritable, Text, OrderBean, NullWritable> {
    OrderBean bean = new OrderBean();

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        final String[] fields = value.toString().split("\t");
        //订单id与jine封装为一个orderBean
        bean.setOrderId(fields[0]);
        bean.setPrice(Double.parseDouble(fields[2]));
        context.write(bean, NullWritable.get());
    }
}
### --- Reducer

package com.yanqi.mr.group;

import org.apache.avro.Schema;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class GroupReducer extends Reducer<OrderBean, NullWritable, OrderBean, NullWritable> {

    //key:reduce方法的key注意是一组相同key的kv的第一个key作为传入reduce方法的key,因为我们已经指定了排序的规则
    //按照金额降序排列,则第一个key就是金额最大的交易数据
    //value:一组相同key的kv对中v的集合
    //对于如何判断key是否相同,自定义对象是需要我们指定一个规则,这个规则通过Groupingcomaprator来指定
    @Override
    protected void reduce(OrderBean key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {
        //直接输出key就是金额最大的交易
        context.write(key, NullWritable.get());
    }
}
### --- Driver

package com.yanqi.mr.group;

import com.yanqi.mr.wc.WordCountDriver;
import com.yanqi.mr.wc.WordCountMapper;
import com.yanqi.mr.wc.WordCountReducer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

public class GroupDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
         /*
        1. 获取配置文件对象,获取job对象实例
        2. 指定程序jar的本地路径
        3. 指定Mapper/Reducer类
        4. 指定Mapper输出的kv数据类型
        5. 指定最终输出的kv数据类型
        6. 指定job处理的原始数据路径
        7. 指定job输出结果路径
        8. 提交作业
         */
//        1. 获取配置文件对象,获取job对象实例
        final Configuration conf = new Configuration();

        final Job job = Job.getInstance(conf, "GroupDriver");
//        2. 指定程序jar的本地路径
        job.setJarByClass(GroupDriver.class);
//        3. 指定Mapper/Reducer类
        job.setMapperClass(GroupMapper.class);
        job.setReducerClass(GroupReducer.class);
//        4. 指定Mapper输出的kv数据类型
        job.setMapOutputKeyClass(OrderBean.class);
        job.setMapOutputValueClass(NullWritable.class);
//        5. 指定最终输出的kv数据类型
        job.setOutputKeyClass(OrderBean.class);
        job.setOutputValueClass(NullWritable.class);

        //指定分区器
        job.setPartitionerClass(CustomPartitioner.class);
        //指定使用groupingcomparator
        job.setGroupingComparatorClass(CustomGroupingComparator.class);
        FileInputFormat.setInputPaths(job, new Path("E:\\teach\\hadoop框架\\资料\\data\\GroupingComparator")); //指定读取数据的原始路径
//        7. 指定job输出结果路径
        FileOutputFormat.setOutputPath(job, new Path("E:\\group\\out3")); //指定结果数据输出路径

        //指定reducetask的数量,不要使用默认的一个,分区效果不明显
        job.setNumReduceTasks(2);
//        8. 提交作业
        final boolean flag = job.waitForCompletion(true);
        //jvm退出:正常退出0,非0值则是错误退出
        System.exit(flag ? 0 : 1);

    }
}
四、编译打印

 
 
 
 
 
 
 
 
 

Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
                                                                                                                                                   ——W.S.Landor

 

posted on   yanqi_vip  阅读(26)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示