在地图中排序减少

时间:2016-03-15 14:22:00

标签: java hadoop mapreduce

我试图在map的map reduce-transpose中实现一个简单的问题。 输入:

   1 2 3 
   4 5 6 
   7 8 9 

所需的输出 -

   1 4 7 
   2 5 8 
   7 8 9 

我的地图输出是

(0,1) (1,4), (2,7), (0,2) (1,5), (2,8)

等等。

我希望将reducer方法用作0-{1,2,7} , 1-{4,5,8}并直接使用write以序列化形式编写对象。但是洗牌和排序并没有给出所需的输出。在map方法之后,我得到输出为0-{1,7,2} , 1-{5,4,8}

如果我的密钥很常见,SS在这种情况下是如何工作的。此案例的解决方案也将是什么。

4 个答案:

答案 0 :(得分:1)

键将在进入reduce阶段时进行排序,给定值集中的值将不会被排序 传递给reducer的值不能保证顺序,这不是Hadoop的工作方式。

你的问题是(如你所说)一个简单的问题' [在许多其他不同的框架和范例中]。这个问题是map reduce的一个简单(或适当的)问题。

您的情况的解决方案是使用更复杂的键来确保输出符合您最初的顺序,或者通过辅助排序映射减少作业来创建复合键,从键和单个值创建复合键。 / p>

答案 1 :(得分:1)

无法保证减少输入的值顺序。

您可以使用第二个MapReduce程序进行排序 要么 你可以使用比较器。这是一个讨论案例的好博客 https://vangjee.wordpress.com/2012/03/20/secondary-sorting-aka-sorting-values-in-hadoops-mapreduce-programming-paradigm/

答案 2 :(得分:0)

您可以构造一个也包含列索引的值。

public class ColumnValue implements Writable{


    public double column;
    public double value;

    public PartialWritablePhase1(long column, double value){
        this.column = column;
        this.value = value;     
    }


    @Override
    public void readFields(DataInput in) throws IOException {
        this.column = in.readLong();
        this.value = in.readDouble();
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeLong(column);
        out.writeDouble(value);


    }

    @Override
    public String toString() {
            return column+" "+value;
}


}

然后你可以在减速机中使用它

public void reduce(LongWritable key, Iterable<ColumnValue> values, Context context)
            throws IOException, InterruptedException {

        for (ColumnVal val : values) {
            //Store values of column in OrderedByColumn an ordered tree set by column
           // or any structure you want
        }


        Iterator<ColumnValue> keySetIterator = OrderedByColumn.iterator();

        while(keySetIterator.hasNext()){

          context.write(new LongWritable(key.get()), keySetIterator.next());
        }


    }

答案 3 :(得分:0)

强制对Reducer中的值进行排序的唯一方法是创建自定义组合键并实现自己的组比较器。这将实现你想要的。

public class CompositeKey implements WritableComparable<CompositeKey> {
    private int id;
    private int order;

    @Override
    public void readFields(DataInput in) throws IOException {
        id = in.readInt();
        order = in.readInt();
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeInt(id);
        out.writeInt(order);
    }

    @Override
    public int hashCode() {
        return id;
    }

    @Override
    public int compareTo(CompositeKey other) {
        if(this.id != other.id) {
            return this.id - other.id;
        }
        return this.order - other.order;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }
}

id字段对应于Mapper输出的键。订单字段对应于您希望为Reducer中的每个键显示值的顺序。 例如,你的Mapper现在应该为第一个元素输出(key:{id = 0,order = 0},value:1),并为第二个元素输出(key:{id = 0,order = 1},value:2)。这样您就可以订购元素了。

最后,为了让您的键值对仅按键ID分组,您需要编写自己的组比较器。

public class CompKeyGroupComparator extends WritableComparator {
    public CompKeyGroupComparator() {
        super(CompositeKey.class, true);
    }

    @Override
    public int compare(WritableComparable a, WritableComparable b) {
        CompositeKey lKey = (CompositeKey) a;
        CompositeKey rKey = (CompositeKey) b;
        return lKey.getId() - rKey.getId();
    }
}

设置GroupComparator:

job.setGroupingComparatorClass(CompKeyGroupComparator.class);

现在,您的reducer将使用您在Mappers中提供的顺序获取值。 0- {1,2,7},1- {4,5,8}等。