23

我想知道为什么在二级mapreduce中使用分组比较器。

根据二次排序的权威指南示例

我们希望键的排序顺序是按年份(升序)然后按温度(降序):

1900 35°C
1900 34°C
1900 34°C
...
1901 36°C
1901 35°C

通过设置一个 partitioner 来按 key 的 year 部分进行分区,我们可以保证同一年的记录去同一个 reducer。然而,这仍然不足以实现我们的目标。partitioner 确保只有一个 reducer 接收一年内的所有记录;它不会改变 reducer 在分区中按键分组的事实。

既然我们已经编写了自己的分区器,它将负责将映射输出键发送到特定的减速器,那么我们为什么要对它进行分组。

提前致谢

4

4 回答 4

37

为了支持所选的答案,我补充说:

这个解释

**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

Partitioner : 将 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.]]**
于 2013-11-01T23:02:50.243 回答
25

让我改进一下语句“......照顾到特定减速器的映射输出键”。

Reducer 实例与 reduce 方法:每个 Reduce 任务创建一个 JVM,每个 JVM 都有一个 Reducer 类的实例。这是 Reducer 实例(我从现在开始称之为 Reducer)。在每个 Reducer 中,reduce 方法被调用多次,具体取决于在'key grouping'上。每次调用reduce时,'valuein'都有一个map输出值列表,这些值由你在'grouping comparison'中定义的键分组。默认情况下,分组比较器使用整个map输出键。

例子中map output key改为'year and temperature'来实现排序。除非你定义一个分组比较器,只使用map output key的'year'部分,否则你不能做同一年的所有记录转到相同的 reduce 方法调用。

于 2013-02-07T05:53:07.580 回答
2

您需要引入一个由年份和温度组合而成的中间键;对自然键(年份)进行分区并引入一个比较器,该比较器将对整个复合键进行排序。没错,通过按年份进行分区,您将在同一个减速器中获得一年的所有数据,因此比较器将有效地按温度对每年的数据进行排序。

于 2013-02-07T03:19:29.193 回答
1

默认的 partitioner 计算 key 的 hash,那些 hash 值相同的 key 会被发送到同一个 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());
}

}

于 2014-06-19T23:49:41.967 回答