我想知道为什么在第二种mapreduce中使用分组比较器。
根据二级排序的权威指南示例
我们希望键的排序顺序为年(升序),然后是 温度(下降):
1900 35°C
1900 34°C
1900 34°C
...
1901 36°C
1901 35°C
通过按键的年份部分设置分区来分区,我们可以保证 同年的记录转到相同的减速机。这仍然不足以实现我们的目标 然而,目标。分区程序仅确保一个reducer接收所有记录 一年;它不会改变reducer在分区内按键分组的事实。
因为我们已经编写了我们自己的分区器来处理特定reducer的map输出键,所以我们为什么要对它进行分组。
提前致谢
答案 0 :(得分:35)
为了支持我选择的答案,我补充说:
**Input**:
symbol time price
a 1 10
a 2 20
b 3 30
**Map output**: create composite key\values like so:
> symbol-time time-price
>
>**a-1** 1-10
>
>**a-2** 2-20
>
>**b-3** 3-30
分区程序:将a-1和a-2键路由到同一个reducer,尽管键不同。它还将b-3路由到一个单独的减速器。
GroupComparator :一旦复合键\值到达reducer而不是reducer得到
>(**a-1**,{1-10})
>
>(**a-2**,{2-20})
由于合成后的唯一键值,上述情况会发生。
组比较器将确保减速器得到:
(a-1,{**1-10,2-20**})
分组值的关键字将是组中第一个出现的值。这可以通过密钥比较器来控制。
**[[In a single reduce method call.]]**
答案 1 :(得分:23)
让我改进声明“......照顾到特定减速器的地图输出键”。
Reducer Instance vs reduce方法: 每个Reduce任务创建一个JVM,每个JVM都有一个Reducer类实例。这是Reducer实例(我从现在开始称之为Reducer)。在每个Reducer中,根据'key grouping'调用reduce方法多次。每次调用reduce时,'valuein'都有一个地图输出值列表,按照你在'分组比较器'中定义的键分组。默认情况下,分组比较器使用整个地图输出键。
在示例中,地图输出键被更改为“年份和温度”以实现排序。除非您定义仅使用地图输出键的“年”部分的分组比较器,否则您无法进行所有记录同年去同一个reduce方法调用。
答案 2 :(得分:2)
您需要引入一个中间密钥,它是年份和温度的组合;对自然键(年份)进行分区,并引入一个比较器,对整个复合键进行排序。你是对的,通过分割年份,你可以在同一个减速器中获得一年的所有数据,因此比较器将根据温度有效地对每年的数据进行排序。
答案 3 :(得分:1)
默认分区程序计算密钥的哈希值,具有相同哈希值的密钥将发送到同一个reducer。如果您在映射器中发出了复合(自然+扩充)键,并且如果要将具有相同自然键的键发送到同一个reducer,则必须实现自定义分区器。
public class SimplePartitioner implements Partitioner {
@Override
public int getPartition(Text compositeKey, LongWritable value, int numReduceTasks) {
//Split the key into natural and augment
String naturalKey = compositeKey.toString().split("separator")
return naturalKey.hashCode();
}
}
现在,如果您希望数据分区中的所有相关行都发送到单个reducer ,您还必须实现仅考虑自然键的分组比较器
public class SimpleGroupingComparator extends WritableComparator {
@Override
public int compare(Text compositeKey1, Text compositeKey2) {
return compare(compositeKey1.getNaturalKey(),compositeKey2.getNaturalKey());
}
}