shuffle的分组

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

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

默认的类型

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

  1. wc:
  2. 000000000000000000000000000
  3. hadoop----------------64
  4. hadoop----------------64
  5. hadoop----------------64
  6. hadoop----------------64
  7. 000000000000000000000000000
  8. hadoophello----------------1
  9. hadoophello----------------1
  10. hadoophello----------------1
  11. hadoophello----------------1
  12. 相同的key为一组
  13. 默认的是key一直随着value指针变化而变化的 只不过默认的key都是一样的

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

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

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

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

分组和排序冲突

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

  1. 课程 姓名 成绩
  2. computer liujialing 98
  3. computer huangbo 96
  4. computer liutao 95
  5. math huangdatou 99
  6. math liuyifei 98
  7. math liutao 95
  8. map的输出的key:自定义类型(课程 姓名 成绩)
  9. 排序:按照成绩
  10. 分组:课程
  11. comparaTo(){
  12. 先按课程
  13. 成绩
  14. }
  15. 但是实际的上的分组是根据comparaTo()方法,
  16. 按照:课程+成绩相同的划分为一组
  17. 每个课程的前三:
  18. 要求:保证reduce一次性可以接受的数据是同一门课程的
  19. 实际:(课程+成绩)相同的划分为一组
  20. 结果:排序和分组冲突了
  21. 解决:
  22. 分组不能使用刚才的排序的规则的了,需要自定义分组
  23. 排序:按照成绩
  24. 分组:课程
  25. 自定义分组:
  26. 分组:课程
  27. 分组的底层:
  28. map输出所有的key进行比较:
  29. - 相同的key return 0)就认为一组
  30. - 比较的过程中,返回的(!= 0)就认为不是同一组

自定义分组

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

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

自定义分组:重写compare

  1. 继承writableComparator

  2. 重写compare()

  3. job中指定

    1. job.setGroupingComparatorClass(MyGroup.class);

常见报错

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

  1. /** Construct for a {@link WritableComparable} implementation. */
  2. protected WritableComparator(Class<? extends WritableComparable> keyClass) {
  3. this(keyClass, null, false);
  4. }
  5. protected WritableComparator(Class<? extends WritableComparable> keyClass,
  6. boolean createInstances) {
  7. this(keyClass, null, createInstances);
  8. }
  9. //参数1 比较的对象类型的class ScoreBean
  10. //参数2 配置文件对象
  11. //参数3---是否创建WritableComparable,这个对象默认false代表不创建
  12. protected WritableComparator(Class<? extends WritableComparable> keyClass,
  13. Configuration conf,
  14. boolean createInstances) {
  15. }

自定义分组例子

  1. import org.apache.hadoop.io.WritableComparable;
  2. import org.apache.hadoop.io.WritableComparator;
  3. /**
  4. * 自定义分组
  5. * @author Administrator
  6. *
  7. */
  8. public class MyGroup extends WritableComparator{
  9. //写构造方法去调用父类,三个参数的最后一个参数要写成true
  10. public MyGroup() {
  11. //创建需要的比较对象
  12. super(ScoreBean.class,true);
  13. }
  14. //重写
  15. /**
  16. * 两个参数 代表两个比较对象 map的key
  17. */
  18. @Override
  19. public int compare(WritableComparable a, WritableComparable b) {
  20. //按照课程进行分组
  21. ScoreBean asb=(ScoreBean)a;
  22. ScoreBean bsb=(ScoreBean)b;
  23. return asb.getName().compareTo(bsb.getName());
  24. }
  25. }

结果文件

  1. 排序:分数
  2. 分组:课程
  3. =========================
  4. computer huangjiaju 83.2-----------(null)
  5. computer huangjiaju 83.2-----------(null)
  6. computer liutao 83.0-----------(null)
  7. =========================
  8. math huangxiaoming 83.0-----------(null)
  9. =========================
  10. english huanglei 83.0-----------(null)
  11. =========================
  12. computer liutao 83.0-----------(null)
  13. 没有显示3个的原因:先进行的排序,再进行的分组
  14. 排完序:
  15. computer huangjiaju 83.2-----------(null)
  16. computer huangjiaju 83.2-----------(null)
  17. computer liutao 83.0-----------(null)
  18. math huangxiaoming 83.0-----------(null)
  19. english huanglei 83.0-----------(null)
  20. computer liutao 83.0-----------(null)
  21. 分组在排序的基础上进行的:判断相邻的
  22. computer huangjiaju 83.2-----------(null)
  23. computer huangjiaju 83.2-----------(null)
  24. computer liutao 83.0-----------(null)
  25. -> 为一组
  26. math huangxiaoming 83.0-----------(null)
  27. -> 为一组
  28. english huanglei 83.0-----------(null)
  29. -> 为一组
  30. computer liutao 83.0-----------(null)
  31. 排序的时候需要将分组的字段放在一起
  32. 排序:课程,分数
  33. 分组:课程

排序分组的组合

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

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

    • 排序:c a b
    • 分组:c

补充

reduce中的迭代器:摄入量

  1. 1. 只能迭代一次,迭代的过程中是指针的操作
  2. > 只要迭代一次 指针调到末尾
  1. 迭代器中的数据对应的一组的所有的value

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

输入reduce中的结果:

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