【问题标题】:Can Hadoop ReflectionUtils initialize enums?Hadoop ReflectionUtils 可以初始化枚举吗?
【发布时间】:2018-03-29 18:40:15
【问题描述】:

我需要在 Mapper 和 Reducer 之间传递 Enum Bucket 类型的列表,我已经根据 implementation-of-an-arraywritable-for-a-custom-hadoop-type 实现了自定义 BucketArrayWritable,并且 Bucket Enum 有一个无参数构造函数,但我总是得到错误

java.lang.RuntimeException: java.lang.NoSuchMethodException: Bucket.<init>()
    at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:131)
    at org.apache.hadoop.io.WritableFactories.newInstance(WritableFactories.java:58)
    at org.apache.hadoop.io.WritableFactories.newInstance(WritableFactories.java:64)
    at org.apache.hadoop.io.ArrayWritable.readFields(ArrayWritable.java:95)
    at org.apache.hadoop.io.serializer.WritableSerialization$WritableDeserializer.deserialize(WritableSerialization.java:71)
    at org.apache.hadoop.io.serializer.WritableSerialization$WritableDeserializer.deserialize(WritableSerialization.java:42)
    at org.apache.hadoop.mapreduce.task.ReduceContextImpl.nextKeyValue(ReduceContextImpl.java:139)
    at org.apache.hadoop.mapreduce.task.ReduceContextImpl.nextKey(ReduceContextImpl.java:114)
    at org.apache.hadoop.mapreduce.lib.reduce.WrappedReducer$Context.nextKey(WrappedReducer.java:296)
    at org.apache.hadoop.mapreduce.Reducer.run(Reducer.java:163)
    at org.apache.hadoop.mapred.ReduceTask.runNewReducer(ReduceTask.java:610)
    at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:444)
    at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:449)
Caused by: java.lang.NoSuchMethodException: com.turn.platform.profile.mapreduce.counting.Bucket.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getDeclaredConstructor(Class.java:2178)
    at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:125)

Reducer 可能想使用反射来初始化对象,但 Enum 构造函数默认是私有的,

8.9.2 Enum Body Declarations
在枚举声明中,没有访问修饰符的构造函数声明是私有的。

我不知道是不是因为 Hadoop ReflectionUtils 找不到私有构造函数

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.function.Predicate;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Writable;


public enum Bucket implements Writable{

    // right bound exclusive
    MAX((count) -> {
        if (count > getValue()) {
            return true;
        }
        return false;
    }, (count, _userId, incre) -> {
        value = count;
        userId = _userId;
    }),
    TOTAL((count) -> {
        return true;
    }),
    BUCKET_0_10((count) -> {
        if (count < 10) {
            return true;
        }
        return false;
    }),
    BUCKET_10_100((count) -> {
        if (count >= 10 && count < 100) {
            return true;
        }
        return false;
    })
    ;

    private static long value = 0;
    private static LongWritable userId = new LongWritable(0);

    private TriConsumer<Long, LongWritable, Long> consumer;
    private Predicate<Long> predicator;

    Bucket() {

    }

    Bucket(Predicate<Long> predicator) {
        this.predicator = predicator;
    }

    Bucket(Predicate<Long> predicator, TriConsumer<Long, LongWritable, Long> consumer) {
        this.consumer = consumer;
        this.predicator = predicator;
    }

    public static long getValue() {
        return value;
    }

    public static void setValue(long newVal) {
        value = newVal;
    }

    public TriConsumer<Long, LongWritable, Long> getConsumer() {
        if (consumer == null) {
            consumer = (count, _userId, incre) -> {
                setValue(getValue() + incre);
                userId = _userId;
            };
        }
        return consumer;
    }

    public Predicate<Long> getPredicator() {
        return predicator;
    }

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

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

【问题讨论】:

    标签: java hadoop reflection enums


    【解决方案1】:

    ReflectionUtils类尝试通过反射来初始化枚举,但是枚举不能这样实例化,这个在Java语言规范中有说明,和this answer说的一样,主要是允许==的使用比较枚举。通过反射,您只能获取现有的引用。

    关于枚举的使用,您可以将枚举“包装”在一个类中,这样您就可以覆盖通常在 reducer 中使用的 equalshashcode 方法。还取决于你在做什么WritableUtils 有方法writeEnumreadEnum。您可以在this answer 中查看有关如何实现包装类的更多信息。

    【讨论】:

    • 您好,感谢您的回答。我实际上已经阅读了所有这些答案。我尝试使用包装类来保存枚举,但枚举是来自answer 的静态,并且包装类的所有实例共享相同的枚举,这不是我想要的,你有什么想法吗?谢谢
    • 来自answer,似乎包装类的所有实例都将共享相同的枚举,所以我认为可以在映射器和reducers之间传递枚举
    • 第一个答案是指嵌套枚举,是的,它们是静态的。你应该只使用枚举到 difference 类,你的 Writable 是有状态的,所以你必须在类中实现它,然后为每个实例使用你想要的变量,例如值不应该是静态的
    • 对不起,最后一条评论应该不可能将枚举作为映射器和reducer之间的类传递
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    • 2011-05-23
    相关资源
    最近更新 更多