Job job = new Job(conf, "MaxTemperature");
job.setJarByClass(MaxTemperature.class);
job.setMapperClass(MaxTemperatureMapper.class);
通常,每个Map会产生大量的输出,combiner类的作用就是在Map端对输出先做一次合并,以减少传输到reducer的数据量。
另外,需要注意的是,根据框架要求,combiner的输入输出类型必须和mapper的输出和reducer的输入类型一致。
Combiner函数的示例如下:
我们以计算特定的key对应的平均值为例,展示一下combiner的用法:
Mapper:
Class Mapper
method Map(Long, String)
Emit(String, Integer)
Combiner:
class Combiner method Combine(String t, Integers [r1, r2, . . .]) sum ← 0 cnt ← 0 for all integer r ∈ integers [r1, r2, . . .] do sum ← sum + r cnt ← cnt + 1 Emit(String t, pair (sum, cnt)) // 分离sum和cnt
Reducer:
class Reducer method Reduce(String t, pairs [(s1, c1), (s2, c2) . . .]) sum ← 0 cnt ← 0 for all pair (s, c) ∈ pairs [(s1, c1), (s2, c2) . . .] do sum ← sum + s cnt ← cnt + c ravg ← sum/cnt Emit(String t, Integer ravg)
乍一看应该没有问题,但是不幸的是,这个combiner是不正确的。因为框架要求,combiner的输入输出类型必须和mapper的输出以及reducer的输入类型一致,更应是和Reducer的输入输出类型一致。即,当Combiner类正确的情况下,可以完全删除而对程序的运行结果没有任何影响,只是对于数据量大的job执行时间会变长。而上面将Combiner删除后,程序就会出错。这时候Mapper的输出类型和Reducer的输入类型不一致。所以会出现这个问题
改变的方式非常简单,把Mapper的输出包装一下即可:
class Mapper method Map(String t, Integer r) Emit(String t, pair (r, 1)) class Combiner method Combine(String t, pairs [(s1, c1), (s2, c2) . . .]) sum ← 0 cnt ← 0 for all pair (s, c) ∈ pairs [(s1, c1), (s2, c2) . . .] do sum ← sum + s cnt ← cnt + c Emit(String t, pair (sum, cnt)) class Reducer method Reduce(String t, pairs [(s1, c1), (s2, c2) . . .]) sum ← 0 cnt ← 0 for all pair (s, c) ∈ pairs [(s1, c1), (s2, c2) . . .] do sum ← sum + s cnt ← cnt + c ravg ← sum/cnt Emit(String t, integer ravg)
//job.setCombinerClass(MaxTemperatureReducer.class);
job.setReducerClass(MaxTemperatureReducer.class);
Partitioner负责对map中间输出键值对按键进行分区,用键或者键的子集来获得分区,典型的是用Hash函数来完成。
分区的总数目和当然工作的reduce任务的总个数相同(reduce任务个数可以通过job.setNumReduceTasks(tasks)进行设置),
因此,这种分组使得发送到reduce任务的中间键值对(记录条数)减少。
PartitionerClass需要继承自Partitioner类,并重载它的getPartition方法。
/** * @param key 将要被分组的键 * @param value 实体的值 * @param numPartitions 总的分组数目 * @return 返回给定key的分组个数 */ int getPartition(K2 key, V2 value, int numPartitions);
PartionerClass的示例代码如下:
public static class CatPartiotner extends Partitioner<Text,Text>{ @Override public int getPartition(Text key, Text value, int numPartitions){ String[] parts=key.toString().split("-");
if(parts.length==2){
return Math.abs(parts[0],hashCode())%numPartitions;
}
return Math.abs(key.toString().hashCode())%numPartitions; } }
然后在job中设置Partitioner Class:
//job.setPartitionerClass(cls);
// job.setInputFormatClass(Class<? extends InputFormat> cls); //设置job的输入格式
// job.setOutputFormatClass(Class<? extends InputFormat> cls); //设置job的输出格式
定义一个比较器,对于Reducer的一个单一的调用reduce(Obect,Iterable,Context),该比较器控制哪些些键被聚合在一起。按照键值关系进行分组。
job.setGroupingComparatorClass(Class<? extends RawComparator> cls)
定义一个比较器,确定在这些键被传递给Reducer之前是以何种方式排序的。主要是对键进行排序。
job.setSortComparatorClass(Class<? extends RawComparator> cls )
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//job.setNumReduceTasks(tasks);
for(int i=0;i<otherArgs.length-1;i++)
FileInputFormat.addInputPath(job, new Path(otherArgs[i]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length-1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
安徽隆兴禽业(www.58lxqy.com)全年大量供应状元红鸡苗(红玉鸡苗)、固始鸡土鸡苗、淮南王土鸡苗,散养鸡苗,大红公鸡苗及各类土鸡种蛋。批发订购:13075005200 QQ:1170693418 地址:阜阳市太和县倪邱镇孙庙105国道东侧。
安徽鸡苗,阜阳鸡苗,安徽土鸡苗,阜阳土鸡苗,鸡苗孵化,河南鸡苗,山东鸡苗,河南土鸡苗,山东土鸡苗,固始鸡,淮南王,纯红肉杂,纯红公鸡。