enum值实现hadoop的可写接口

nwlqm0z1  于 2021-06-03  发布在  Hadoop
关注(0)|答案(3)|浏览(385)

假设我有一个枚举:

public enum SomeEnumType implements Writable {
  A(0), B(1);

  private int value;

  private SomeEnumType(int value) {
    this.value = value;
  }

  @Override
  public void write(final DataOutput dataOutput) throws IOException {
    dataOutput.writeInt(this.value);
  }

  @Override
  public void readFields(final DataInput dataInput) throws IOException {
    this.value = dataInput.readInt();
  }
}

我想把它的一个示例作为其他类示例的一部分来传递。
equals不起作用,因为它不会考虑枚举的内部变量,而且所有枚举示例在编译时都是固定的,不能在其他地方创建。
这是否意味着我不能在hadoop中通过网络发送枚举,或者有解决方案?

jhiyze9q

jhiyze9q1#

对于hadoop中的枚举,我通常和首选的解决方案是通过它们的序数值序列化枚举。

public class EnumWritable implements Writable {

    static enum EnumName {
        ENUM_1, ENUM_2, ENUM_3
    }

    private int enumOrdinal;

    // never forget your default constructor in Hadoop Writables
    public EnumWritable() {
    }

    public EnumWritable(Enum<?> arbitraryEnum) {
        this.enumOrdinal = arbitraryEnum.ordinal();
    }

    public int getEnumOrdinal() {
        return enumOrdinal;
    }

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

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

    public static void main(String[] args) {
        // use it like this:
        EnumWritable enumWritable = new EnumWritable(EnumName.ENUM_1);
        // let Hadoop do the write and read stuff
        EnumName yourDeserializedEnum = EnumName.values()[enumWritable.getEnumOrdinal()];
    }

}

显然它有缺点:序数可以改变,所以如果你交换 ENUM_2ENUM_3 并读取先前序列化的文件,这将返回另一个错误的枚举。
因此,如果您事先知道enum类,则可以编写enum的名称并按如下方式使用:

enumInstance = EnumName.valueOf(in.readUTF());

这将稍微占用更多的空间,但更便于保存对枚举名称的更改。
完整示例如下所示:

public class EnumWritable implements Writable {

    static enum EnumName {
        ENUM_1, ENUM_2, ENUM_3
    }

    private EnumName enumInstance;

    // never forget your default constructor in Hadoop Writables
    public EnumWritable() {
    }

    public EnumWritable(EnumName e) {
        this.enumInstance = e;
    }

    public EnumName getEnum() {
        return enumInstance;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeUTF(enumInstance.name());
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        enumInstance = EnumName.valueOf(in.readUTF());
    }

    public static void main(String[] args) {
        // use it like this:
        EnumWritable enumWritable = new EnumWritable(EnumName.ENUM_1);
        // let Hadoop do the write and read stuff
        EnumName yourDeserializedEnum = enumWritable.getEnum();

    }

}
cx6n0qe3

cx6n0qe32#

我对hadoop一无所知,但根据接口文档,您可能可以这样做:

public void readFields(DataInput in) throws IOException {
     // do nothing
}

public static SomeEnumType read(DataInput in) throws IOException {
    int value = in.readInt();
    if (value == 0) {
        return SomeEnumType.A;
    }
    else if (value == 1) {
        return SomeEnumType.B;
    }
    else {
        throw new IOException("Invalid value " + value);
    }
}
szqfcxe2

szqfcxe23#

writableutils提供了方便的方法,使之更容易实现。

WritableUtils.writeEnum(dataOutput,enumData);
enumData = WritableUtils.readEnum(dataInput,MyEnum.class);

相关问题