5

1 つの Mapper クラスで、1 回の実行で (同じ型の) 複数のキーと値のペアを生成できますか?

次のようにマッパーでキーと値のペアを出力します。

context.write(key, value);

これは、キーの縮小 (および例示) バージョンです。

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import org.apache.hadoop.io.ObjectWritable;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;


public class MyKey extends ObjectWritable implements WritableComparable<MyKey> {

    public enum KeyType {
        KeyType1,
        KeyType2
    }

    private KeyType keyTupe;
    private Long field1;
    private Integer field2 = -1;
    private String field3 = "";


    public KeyType getKeyType() {
        return keyTupe;
    }

    public void settKeyType(KeyType keyType) {
        this.keyTupe = keyType;
    }

    public Long getField1() {
        return field1;
    }

    public void setField1(Long field1) {
        this.field1 = field1;
    }

    public Integer getField2() {
        return field2;
    }

    public void setField2(Integer field2) {
        this.field2 = field2;
    }


    public String getField3() {
        return field3;
    }

    public void setField3(String field3) {
        this.field3 = field3;
    }

    @Override
    public void readFields(DataInput datainput) throws IOException {
        keyTupe = KeyType.valueOf(datainput.readUTF());
        field1 = datainput.readLong();
        field2 = datainput.readInt();
        field3 = datainput.readUTF();
    }

    @Override
    public void write(DataOutput dataoutput) throws IOException {
        dataoutput.writeUTF(keyTupe.toString());
        dataoutput.writeLong(field1);
        dataoutput.writeInt(field2);
        dataoutput.writeUTF(field3);
    }

    @Override
    public int compareTo(MyKey other) {
        if (getKeyType().compareTo(other.getKeyType()) != 0) {
            return getKeyType().compareTo(other.getKeyType());
        } else if (getField1().compareTo(other.getField1()) != 0) {
            return getField1().compareTo(other.getField1());
        } else if (getField2().compareTo(other.getField2()) != 0) {
            return getField2().compareTo(other.getField2());
        } else if (getField3().compareTo(other.getField3()) != 0) {
            return getField3().compareTo(other.getField3());
        } else {
            return 0;
        }
    }

    public static class MyKeyComparator extends WritableComparator {
        public MyKeyComparator() {
            super(MyKey.class);
        }

        public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
            return compareBytes(b1, s1, l1, b2, s2, l2);
        }
    }

    static { // register this comparator
        WritableComparator.define(MyKey.class, new MyKeyComparator());
    }
}

これは、Mapper で両方のキーを出力しようとした方法です。

MyKey key1 = new MyKey();
key1.settKeyType(KeyType.KeyType1);
key1.setField1(1L);
key1.setField2(23);

MyKey key2 = new MyKey();
key2.settKeyType(KeyType.KeyType2);
key2.setField1(1L);
key2.setField3("abc");

context.write(key1, value1);
context.write(key2, value2);

ジョブの出力形式クラスは次のとおりです: org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat

これを述べているのは、他の出力形式クラスでは、出力が追加されず、書き込みメソッドの実装でコミットされているだけだからです。

また、Mapper と Context には次のクラスを使用しています: org.apache.hadoop.mapreduce.Mapper org.apache.hadoop.mapreduce.Context

4

1 に答える 1

11

1 つの map タスクでコンテキストに複数回書き込むことはまったく問題ありません。

ただし、キー クラスにいくつかの問題がある場合があります。キーを実装するときはいつでも、 andメソッドWritableComparableも実装する必要があります。これらは で定義されているため、WritableComparable インターフェイスの一部ではありませんが、実装を提供する必要があります。equals(Object)hashCode()Object

デフォルトのパーティショナーは、hashCode()メソッドを使用して、各キーと値のペアがどのレデューサーに移動するかを決定します。適切な実装を提供しないと、奇妙な結果が生じる可能性があります。

経験則として、hashCode()または何らかの比較メソッドを実装するときはいつでも、equals(Object)メソッドも提供する必要があります。Objectこれがクラスで定義されている方法であるため、パラメーターとしてan を受け入れることを確認する必要がObjectあります (その実装はおそらくオーバーライドしています)。

于 2011-05-26T16:38:17.063 に答える