减少器按两个值分组

时间:2015-01-30 14:27:36

标签: hadoop mapreduce

我有一个案例,Mapper发出属于子组的数据,子组属于一个组。

我需要将子组中的所有值相加,并找到每个组的所有子组之间的最小值。

所以,我有一个Mapper的输出,看起来像这个

Group 1

group,subgroupId,value
Group1,1,2
Group1,1,3
Group1,1,4
Group1,2,1
Group1,2,2
Group1,3,1
Group1,3,2
Group1,3,5

Group 2

group,subgroupId,value
Group2,4,2
Group2,4,3
Group2,4,4
Group2,5,1
Group2,5,2
Group2,6,1
Group2,6,2

我的输出应该是

Group1, 1, (2+3+4)
Group1, 2, (1+2)
Group1, 3, (1+2+5)

Group1 min = min((2+3+4),(1+2),(1+2+5))

第2组相同。

所以我几乎需要分组两次,第一组由GROUP组成,然后在SUBGROUPID组内。

所以我应该从一个组中发出最小的总和,在给定的例子中,我的reducer应该发出(2,3),因为最小的和是3,它来自id为2的元素。

因此,似乎可以使用reduce两次最佳解决,首先,reduce将获取按id分组的元素,并将传递给按组ID分组的第二个Reducer。

这是否有意义以及如何实施?我见过ChainedMapper和ChainedReducer,但它们不适合这个目的。

由于

2 个答案:

答案 0 :(得分:0)

如果所有数据都可以放入一台机器的内存中,您可以使用一个reducer(job.setNumReducers(1);)和两个临时变量在一个作业中完成所有这些操作。输出在减速器的清理阶段发出。如果你使用新的Hadoop API(支持cleanup()方法),这是伪代码:

int tempKey;
int tempMin;    

setup() {
    tempMin = Integer.MAX_VALUE;
}

reduce(key, values) {
    int sum = 0;
    while (values.hasNext()) {
        sum += values.next();
    }
    if (sum < tempMin) {
        tempMin = sum;
        tempKey = key;
    }
}

cleanup() { //only in the new API
    emit(tempKey, tempMin);
}

答案 1 :(得分:0)

您的方法(总结如下),我将如何做到这一点。

工作1:

  1. 映射器:将id分配给subgroupid
  2. Combiner / Reducer(同一类):查找最小value subgroupid
  3. 工作2:

    1. 映射器:将groupid分配给subgroupid
    2. Combiner / Reducer(同一类):查找最小value groupid
    3. 最好在两个作业中实现,原因如下:

      • 显着简化映射器和缩减器(您不必担心第一次找到所有groupids)。在映射器中查找(groupid, subgroupid)对可能非常重要。编写两个映射器应该是微不足道的。
      • 遵循Tom White in Hadoop: The Definitive Guide (Chapter 6).
      • 给出的地图缩减编程指南
      • Oozie工作流程可以轻松简单地适应从属作业。
      • 中间文件产品(key:subgroupid, value: min value for subgroupid)应该很小,限制了网络资源的使用。