shuffle的分组

map—-shuffle—–reduce
shuffle:分区—-排序—-分组

分组到底是怎么分组的:按照map的key进行分组的

默认的类型

对Reduce的结果进行打印输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
wc:
000000000000000000000000000
hadoop----------------64
hadoop----------------64
hadoop----------------64
hadoop----------------64
000000000000000000000000000
hadoophello----------------1
hadoophello----------------1
hadoophello----------------1
hadoophello----------------1

相同的key为一组
默认的是key一直随着value指针变化而变化的 只不过默认的key都是一样的

自定义的类型:按照自定义类型的comparaTo的方法进行分组的

1
2
3
4
5
6
7
8
9
10
11
12
现根据:科目,再根据成绩,会将相同科目和相同分数的人划分到一组
111111111111111111111111111111
computer huangzitao 72.42857142857143-----------(null)
computer huangxiaoming 72.42857142857143-----------(null)
computer huangzitao 72.42857142857143-----------(null)
computer huangxiaoming 72.42857142857143-----------(null)

map:context.write(sb,null)
computer huangzitao 72.42857142857143-----------(null)
computer huangxiaoming 72.42857142857143-----------(null)
computer huangzitao 72.42857142857143-----------(null)
computer huangxiaoming 72.42857142857143-----------(null)

reduce:默认分组:调用的就是所有类型ComparaTo方法—排序的方法

有的需求中分组和排序如果有冲突,怎么办?

分组和排序冲突

如:求出每门课程中参加考试的学生平均成绩的top3的学生的信息:课程,姓名和平均分

课程   		姓名    	成绩
computer	liujialing	98
computer	huangbo		96
computer	liutao		95
math		huangdatou	99
math		liuyifei	98
math		liutao		95

map的输出的key:自定义类型(课程  姓名   成绩)
排序:按照成绩
分组:课程
comparaTo(){
    先按课程
    成绩
}

但是实际的上的分组是根据comparaTo()方法,
按照:课程+成绩相同的划分为一组


​ 每个课程的前三:
​ 要求:保证reduce一次性可以接受的数据是同一门课程的
​ 实际:(课程+成绩)相同的划分为一组
​ 结果:排序和分组冲突了

​ 解决:
​ 分组不能使用刚才的排序的规则的了,需要自定义分组
​ 排序:按照成绩
​ 分组:课程

自定义分组:
分组:课程
分组的底层:
对map输出所有的key进行比较:- 相同的key (return 0)就认为一组 - 比较的过程中,返回的(!= 0)就认为不是同一组

自定义分组

writableComparator 普通类,定义分组规则的。

1
2
3
4
5
6
7
8
9
默认的分组的比较:
@SuppressWarnings("unchecked")
//map输出的key-----具有比较和序列化能力(WritableComparable)
//参数:WritableComparable
//分组针对map输出的key
public int compare(WritableComparable a, WritableComparable b) {
//默认的分组就是调用的自定义的comparaTo
return a.compareTo(b);
}

自定义分组:重写compare

  1. 继承writableComparator

  2. 重写compare()

  3. job中指定

    1
    job.setGroupingComparatorClass(MyGroup.class);

常见报错

java.lang.Exception: java.lang.NullPointerException
空指针异常的错误:compare() 两个参数的对象默认不会帮我们创建的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/** Construct for a {@link WritableComparable} implementation. */
protected WritableComparator(Class<? extends WritableComparable> keyClass) {
this(keyClass, null, false);
}

protected WritableComparator(Class<? extends WritableComparable> keyClass,
boolean createInstances) {
this(keyClass, null, createInstances);
}

//参数1 比较的对象类型的class ScoreBean
//参数2 配置文件对象
//参数3---是否创建WritableComparable,这个对象默认false代表不创建
protected WritableComparator(Class<? extends WritableComparable> keyClass,
Configuration conf,
boolean createInstances) {

}

自定义分组例子

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
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;

/**
* 自定义分组
* @author Administrator
*
*/
public class MyGroup extends WritableComparator{
//写构造方法去调用父类,三个参数的最后一个参数要写成true
public MyGroup() {
//创建需要的比较对象
super(ScoreBean.class,true);
}

//重写
/**
* 两个参数 代表两个比较对象 map的key
*/
@Override
public int compare(WritableComparable a, WritableComparable b) {
//按照课程进行分组
ScoreBean asb=(ScoreBean)a;
ScoreBean bsb=(ScoreBean)b;
return asb.getName().compareTo(bsb.getName());
}

}

结果文件

排序:分数
分组:课程
=========================
computer	huangjiaju	83.2-----------(null)
computer	huangjiaju	83.2-----------(null)
computer	liutao	83.0-----------(null)
=========================
math	huangxiaoming	83.0-----------(null)
=========================
english	huanglei	83.0-----------(null)
=========================
computer	liutao	83.0-----------(null)

没有显示3个的原因:先进行的排序,再进行的分组
排完序:
    computer	huangjiaju	83.2-----------(null)
    computer	huangjiaju	83.2-----------(null)
    computer	liutao	83.0-----------(null)
    math	huangxiaoming	83.0-----------(null)
    english	huanglei	83.0-----------(null)
    computer	liutao	83.0-----------(null)

分组在排序的基础上进行的:判断相邻的
    computer	huangjiaju	83.2-----------(null)
    computer	huangjiaju	83.2-----------(null)
    computer	liutao	83.0-----------(null)
    -> 为一组
    math	huangxiaoming	83.0-----------(null)
    -> 为一组
    english	huanglei	83.0-----------(null)
    -> 为一组
    computer	liutao	83.0-----------(null)

排序的时候需要将分组的字段放在一起
排序:课程,分数
分组:课程

排序分组的组合

排序的字段中必须包含 分组字段,分组字段必须在排序字段的前面

  • 既有排序 a,b 又有分组 c
    • 排序:c a b
    • 分组:c

补充

reduce中的迭代器:摄入量

1. 只能迭代一次,迭代的过程中是指针的操作

> 只要迭代一次  指针调到末尾
  1. 迭代器中的数据对应的一组的所有的value

    这个迭代器中每一个value都对应一个自己的key

输入reduce中的结果:

1
2
3
4
5
6
7
8
9
111111111111111111111111111111
computer huangzitao 72.42857142857143
computer huangzitao 72.42857142857143-----------(null)
computer huangxiaoming 72.42857142857143-----------(null)
computer huangzitao 72.42857142857143-----------(null)
computer huangxiaoming 72.42857142857143-----------(null)
==============
每一组中的这个key是一直随着value指针移动而移动的
每一个value都会对应一个key值