------------本文笔记整理自《Hadoop海量数据处理:技术详解与项目实战》范东来
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.适用场景:求最大值、最小值、求和等。(如下图:单词计数)
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个分区。
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;
}
}
job.setCombinerClass(MyReducer.class);
job.setPartitionerClass(MyPartitioner.class);
job.setSortComparatorClass(MyWritableComparator.class);