映射JavaRDD时获取java.io.NotSerializableException

时间:2016-11-28 06:58:56

标签: java serialization apache-spark

以下是当我尝试将作业分派给执行程序时导致java.io.NotSerializableException的代码。

    JavaRDD<Row> rddToWrite = dataToWrite.toJavaRDD();
    JavaRDD<String> stringRdd = rddToWrite.map(new Function<Row, String>() {

        /**
         * Serial Version Id
         */
        private static final long serialVersionUID = 6766320395808127072L;

        @Override
        public String call(Row row) throws Exception {
            return row.mkString(dataFormat.getDelimiter());
        }
    });

但是,当我执行以下操作时,任务已成功序列化:

JavaRDD<Row> rddToWrite = dataToWrite.toJavaRDD();
List<String> dataList = rddToWrite.collect().stream().parallel()
                           .map(row -> row.mkString(dataFormat.getDelimiter()))
                           .collect(Collectors.<String>toList());
JavaSparkContext javaSparkContext = new JavaSparkContext(sessionContext.getSparkContext());
JavaRDD<String> stringRDD = javaSparkContext.parallelize(dataList);

任何人都可以帮我指出我在这里做错了吗?

编辑: dataFormat是类中的私有成员字段,其中包含此代码的函数被写入。它是类DataFormat的一个对象,它定义了两个字段,即spark dataformat(例如“com.databricks.spark.csv”)和分隔符(例如“\ t”)。

2 个答案:

答案 0 :(得分:3)

new Function ...创建的匿名类需要对封闭实例的引用,并且序列化该函数需要序列化封闭实例,包括dataFormat 所有其他字段。如果该类未标记为Serializable,或者具有任何不可序列化的非transient字段,则无法正常工作。即使它确实如此,它也会默默地表现得比必要的更糟糕。

不幸的是,要完全解决这个问题,你需要创建一个命名的静态内部类(或者只是一个单独的类),它甚至不能是本地的(因为匿名和local classes in Java都不能是静态的):

static class MyFunction extends Function<Row, String> {
    private String delimiter;
    private static final long serialVersionUID = 6766320395808127072L;

    MyFunction(String delimiter) {
        this.delimiter = delimiter;
    }

    @Override
    public String call(Row row) throws Exception {
        return row.mkString(delimiter);
    }
}

然后

JavaRDD<String> stringRdd = rddToWrite.map(new MyFunction(dataFormat.getDelimiter()));

答案 1 :(得分:3)

当您访问dataFormat时,表示this.dataFormat。 因此,spark会尝试序列化this并遇到NotSerializableException

尝试制作本地副本,如:

DataFormat dataformat = this.dataformat;
JavaRDD<Row> rddToWrite = dataToWrite.toJavaRDD();
JavaRDD<String> stringRdd = rddToWrite.map(new Function<Row, String>() ...

有关详细信息,请参阅 http://spark.apache.org/docs/latest/programming-guide.html#passing-functions-to-spark