- 总结自8.1节:MapReduce的类型 P207-218
MapReduce中map与reduce函数遵循格式如下:
map:(k1, v1) -> list(k2, v2)
reduce:(k2, list(v2))-> list(k3, v3)
一般来说map函数输入的键/值(K1/V1)类型不同于输出类型(K2/V2),但map函数的输出类型需要与reduce的输入类型相同。但reduce的输出类型可以不同于reduce的输入类型。
如果使用combiner函数的话,格式会变为以下:
map:(k1, v1) -> list(k2, v2)
combiner:(k2, list(v2)) -> list(k2, v2)
reduce:(k2, list(v2))-> list(k3, v3)
由上可知,通常combiner函数与reduce函数是相同的,这种情况下,k2类型与k3相同,v2类型与v3相同。区别在于运行的阶段。
分区索引由Partitioner
接口的getPartition
获取。默认情况下,hadoop使用的是其默认实现:Hash分区方式,我们也可通过自己实现该接口然后通过job(job.setPartitionerClass)显式设置。
partition:(k2, v2)-> Integer
TextInputFormat的默认键值为LongWriteable/Text。
为什么我们在Mapper和Reducer中已经声明了相关key和value的类型,我们还需要使用job.setXXX()
方法呢?
答:因为java中的类型擦除:一句话总结就是泛型的类型在进入jvm后被消除,泛型仅仅用于编译器代码检查。详见:https://www.cnblogs.com/drizzlewithwind/p/6101081.html
附表:新API中的相关键值设置函数
属性 | 属性设置方法 | 输入类型 | 中间类型 | 输出类型 | |||
可以设置类型的属性 | |||||||
mapreduce.job.inputformat.class | setInsetInputFormatClass | * | * | ||||
mapreduce.map.output.key.class | setMapOutputKeyClass | * | |||||
mapreduce.map.output.value.class | setMapOutputValueClass | * | |||||
mapreduce.job.output.key.class | setOutputKeyClass | * | |||||
mapreduce.job.output.value.class | setOutputValueClass | * | |||||
类型必须一致的属性 | |||||||
mapreduce.job.map.class | setMapperClass | * | * | * | * | ||
mapreduce.job.combin.class | setCombinerClass | * | * | ||||
mapreduce.job.partitioner.class | setPartitionerClass | * | * | ||||
mapreduce.job.output.key.comparator.class | setSortComparatorClass | ||||||
mapreduce.job.output.group.comarator.class | setGroupingComparatorClass | * | |||||
mapreduce.job.reduce.class | setReducerClass | * | * | * | * | ||
mapreduce.job.outputformat.class | setOutputFormatClass | * | * | ||||
注意事项: 1. job.setPartitionerClass(PartitionClass.class):对key取hash值(或其它处理),进入不同的reduce task 2. job.setSortComparatorClass(SortComparator.class):对进入同一个reduce task的键或键的部分进行排序; 3. job.setGroupingComparatorClass(RawComparator.class):定义一个分组规则。因为进入同一个reduce任务的数据不代表位于同一行 |
在新版本API中,mapreduce的Mapper和Reducer实现由原来的实现接口改为了继承类。因此,在新API中,我们可以不用指定Mapper和Reducer实现,此时使用的是默认实现。
在默认实现中,输入类型为TextInputFormat
,对应的键类型为LongWritable
,表示本行数据开头在文件中的偏移量;对应的值类型为Text
,表示本行数据内容。输出类型为TextOutputFormat
,他将键和值转化成字符串并用字符串分隔,然后一条一条输出。
默认的分区函数的实现是HashPartitioner
,根据相关源码可知,默认的分区方式返回结果与reduce任务个数(等同于分区个数,一个分区对应一个reduce 任务)。又由于默认的reduce个数为1,即以下函数永远返回0。默认分区实现如下
public int getPartition(K2 key, V2 value, int numReduceTasks) {
return (key.hashCode() & 2147483647) % numReduceTasks;
}
一条经验法则:目标reduce保持每个运行5分钟左右,且至少产生一个HDFS块输出比较合适。
对于默认的文本模式(-o text)模式,streaming仅会传递值给mapper而忽略键,对于其他模式,设置stream.map.input.ignorekey
设为true可达到相同效果。
streaming的分隔符属性表详细见:https://www.cnblogs.com/shay-zhangjin/p/7714868.html