MapReduce的Combine操作&shuffle控制&sort控制

------------本文笔记整理自《Hadoop海量数据处理:技术详解与项目实战》范东来

一、Combine操作

1.combine在MapReduce中是一个可选的过程。

2.Hadoop性能很大程度受限于网络带宽,map函数输出的中间结果都是通过网络传递给reduce函数的,所以提高中间结果数据量就可以提高程序运行效率。

3.combine操作是对map中间结果传递给reduce之前先做一次聚合操作,如单词统计中的单词计数,实现了对结果的初步合并。

4.Hadoop不保证combine是否被执行。

5.Combiner没有自己的接口,与Reducer有相同的特征,需要继承Reducer(org.apache.hadoop.mapreduce.Reducer)。

6.Combiner的开启操作:job.setCombinerClass(IntSumReducer.class);,可见,combine操作实际跟reduce操作共用一个函数实现。

7.适用场景:求最大值、最小值、求和等。(如下图:单词计数)

MapReduce的Combine操作&shuffle控制&sort控制_第1张图片

二、shuffle控制

1.shuffle过程是将map中间结果(按分区)分发到reduce上,同一个分区会交由一个reduce处理。

2.控制分区方式,也就控制了shuffle。

3.分区操作是由Partitioner(org.apache.hadoop.mapreduce.Partitioner)的子类完成的,自定义分区操作需要继承Partitioner,实现getPartition方法(处理还未经map处理的键值对,并返回分区结果)。

4.Partitioner抽象类源码,如下:

package org.apache.hadoop.mapreduce;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configurable;

public abstract class Partitioner {
  
  /** 
   * Get the partition number for a given key (hence record) given the total 
   * number of partitions i.e. number of reduce-tasks for the job.
   *   
   * 

Typically a hash function on a all or a subset of the key.

* * @param key the key to be partioned. * @param value the entry value. * @param numPartitions the total number of partitions. * @return the partition number for the key. */ public abstract int getPartition(KEY key, VALUE value, int numPartitions); }

5.Hadoop自带的实现类:

HashPartitioner类(Hadoop默认使用):基于key的hash值分区,如下源码:

TotalOrderPartitioner类:基于区间分区

package org.apache.hadoop.mapreduce.lib.partition;

import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.mapreduce.Partitioner;

public class HashPartitioner extends Partitioner {

  public int getPartition(K key, V value,
                          int numReduceTasks) {
    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
  }

}

6.自定义分区,继承Partitioner,实现基于value的hash二分分区,如下:

package com.hadoop.partition;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;

/*
 * 自定义分区操作:按value值进行hash二分,控制shuffle
 * 如果value > 10000,则是第一个分区;否则,为第二个分区。
 * 开启方式:job.setPartitionerClass(MyPartitioner.class);
 */
public class MyPartitioner extends Partitioner{

	@Override
	public int getPartition(Text key, IntWritable value, int numReduceTasks) {
		return (new Boolean(value.get() > 10000).hashCode() & Integer.MAX_VALUE) % numReduceTasks;
	}
	
}

7.最终的分区个数由reduce任务的配置个数决定(因为分区求解中都对numReduceTasks求余)。所以如果reduce任务默认为1,那么最终将只有1个分区。

 

三、sort控制

1.MapReduce过程一共发生了3次排序操作,这3次排序是MR计算框架的默认行为,我们不能控制其是否发生,但可以控制排序的规则。

2.Hadoop封装的Java类型都实现了WritableComparable接口,即都能用compareTo方法比较。

3.Hadoop默认的比较方式是通过调用WritableComparator的compare方法将两个WritableComparable实现类的实例进行比较的。

4.自定义比较器要继承WritableComparator类,重写compare方法,代码如下:

package com.hadoop.sort;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;

/*
 * 自定义比较器:比较key对5取模后的大小,控制sort
 * 开启方式:job.setSortComparatorClass(MyWritableComparator.class);
 */
public class MyWritableComparator extends WritableComparator {
	
	protected MyWritableComparator() {
		super(IntWritable.class, true);
	}

	@Override
	public int compare(WritableComparable a, WritableComparable b) {
		IntWritable x = (IntWritable) a;
		IntWritable y = (IntWritable) b;
		return (x.get() % 5 - y.get() % 5) > 0 ? 1 : -1;
	}
	
}

四、开启自定义combine、分区、排序的方式

job.setCombinerClass(MyReducer.class);
job.setPartitionerClass(MyPartitioner.class);
job.setSortComparatorClass(MyWritableComparator.class);

 

你可能感兴趣的:(MapReduce)