====
案例:分组求top1
自定义GroupingComparator求取topN
GroupingComparator是mapreduce当中reduce端的一个功能组件,主要的作用是决定哪些数据作为一组,调用一次reduce的逻辑,默认是每个不同的key,作为多个不同的组,每个组调用一次reduce逻辑,我们可以自定义GroupingComparator实现不同的key作为同一个组,调用一次reduce逻辑
3.1 需求
有如下订单数据
订单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 222.8
现在需要求出每一个订单中成交金额最大的一笔交易
3.2 分析
1、利用“订单id和成交金额”作为key,可以将map阶段读取到的所有订单数据按照id分区,按照金额排序,发送到reduce
2、在reduce端利用groupingcomparator将订单id相同的kv聚合成组,然后取第一个即是最大值
第一步:读取文件,解析成key, value对。
第二步:自定义map逻辑,接收k1,v1,转换成新的k2,v2。
k1: LongWritable; v1: Text
k2: OrderBean(orderId, price); v2: NullWritable
第一点:一定要保证:相同orderID的数据到同一个reduce里面去,以订单id作为key2。
第二点:我们相同的订单id的数据,需要按照金额进行排序。需要按照谁排序,就把谁作为k2。金额作为key2。
所以,定义一个orderBean,有两个属性,一个是orderId订单号,一个是price金额。以OrderBean作为key2。
默认分区规则HashPartitioner
自定义分区规则,以订单id作为分区一句,相同的订单id发送到同一个reduce里面去。
排序以OrderBean里面的金额进行排序。注意,排序有要求,只有相同的orderId里面的金额才需要排序。
第三步:自定义分区,以我们的OrderBean里面的orderId作为分区的依据。
第四步:排序。按照相同订单的金额进行排序,不同订单金额没有可比性。
第五步:规约。
第六步:分组。接收k2,v2。
k2: OrderBean(orderId, price); v2: NullWritable
每一条数据,都是一个独立的组,每一条数据分完组后,都要去独立地调用一次reduce逻辑。
需要自定义分组,我们的任务相同订单id的数据是同一个组里面的数据,给我们合并为一组。
相同的订单id作为一组,我们这个组里面有多条数据,但是只给我们显示了金额最大的那一条。(分组求top1)
第七步:自定义reduce逻辑接收k2,v2,直接输出k2,就是我们的最大值top1。
第八步:输出文件。
代码实现
第一步:定义OrderBean
package cn.itcast.demo5.top1;
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;
private Double price;
/**
* 比较器
* @param o
* @return
*/
@Override
public int compareTo(OrderBean o) {
//第一个问题:不同订号,不用比较价格排序
int i = this.orderId.compareTo(o.orderId);
if(i ==0){
//订单号相等了
//继续比较交个
i = this.price.compareTo(o.price);
i = -i;
}
return i;
}
/**
* 序列化的方法
* @param out
* @throws IOException
*/
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(orderId);
out.writeDouble(price);
}
/**
* 反序列化的方法
* @param in
* @throws IOException
*/
@Override
public void readFields(DataInput in) throws IOException {
this.orderId = in.readUTF();
this.price = in.readDouble();
}
public String getOrderId() {