映射JavaRDD时获取java.io.NotSerializableException
以下是我尝试将作业分派给执行者时导致java.io.NotSerializableException的代码映射JavaRDD时获取java.io.NotSerializableException,java,serialization,apache-spark,Java,Serialization,Apache Spark,以下是我尝试将作业分派给执行者时导致java.io.NotSerializableException的代码 JavaRDD<Row> rddToWrite = dataToWrite.toJavaRDD(); JavaRDD<String> stringRdd = rddToWrite.map(new Function<Row, String>() { /** * Serial Version Id
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-rddToWrite=dataToWrite.toJavaRDD();
JavaRDD stringRdd=rddToWrite.map(新函数(){
/**
*串行版本Id
*/
私有静态最终长serialVersionUID=6766320395808127072L;
@凌驾
公共字符串调用(行)引发异常{
返回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);
JavaRDD-rddToWrite=dataToWrite.toJavaRDD();
List dataList=rddToWrite.collect().stream().parallel()
.map(行->行.mkString(dataFormat.getDelimiter())
.collect(Collectors.toList());
JavaSparkContext JavaSparkContext=新的JavaSparkContext(sessionContext.getSparkContext());
JavaRDD stringRDD=javaSparkContext.parallelize(数据列表);
有人能帮我指出我做错了什么吗
编辑:
dataFormat是类中包含此代码的函数的私有成员字段。它是DataFormat类的对象,定义了两个字段,即spark DataFormat(例如“com.databricks.spark.csv”)和分隔符(例如“\t”)。由
新函数创建的匿名类…
需要引用封闭实例,序列化函数需要序列化封闭实例,包括dataFormat
和所有其他字段。如果该类未标记为可序列化
,或具有任何不可序列化的非瞬态
字段,则该类将无法工作。即使它这样做了,它也会默默地表现得比必要的还要糟糕
不幸的是,要完全解决这个问题,您需要创建一个命名的静态内部类(或者只是一个单独的类),它甚至不能是本地的(因为既不能是匿名的,也不能是静态的):
静态类MyFunction扩展函数{
私有字符串分隔符;
私有静态最终长serialVersionUID=6766320395808127072L;
MyFunction(字符串分隔符){
this.delimiter=分隔符;
}
@凌驾
公共字符串调用(行)引发异常{
返回row.mkString(分隔符);
}
}
然后
JavaRDD<String> stringRdd = rddToWrite.map(new MyFunction(dataFormat.getDelimiter()));
JavaRDD-stringRdd=rddToWrite.map(新的MyFunction(dataFormat.getDelimiter());
由新函数创建的匿名类…
需要对封闭实例的引用,序列化函数需要序列化封闭实例,包括dataFormat
和所有其他字段。如果该类未标记为可序列化
,或具有任何不可序列化的非瞬态
字段,则该类将无法工作。即使它这样做了,它也会默默地表现得比必要的还要糟糕
不幸的是,要完全解决这个问题,您需要创建一个命名的静态内部类(或者只是一个单独的类),它甚至不能是本地的(因为既不能是匿名的,也不能是静态的):
静态类MyFunction扩展函数{
私有字符串分隔符;
私有静态最终长serialVersionUID=6766320395808127072L;
MyFunction(字符串分隔符){
this.delimiter=分隔符;
}
@凌驾
公共字符串调用(行)引发异常{
返回row.mkString(分隔符);
}
}
然后
JavaRDD<String> stringRdd = rddToWrite.map(new MyFunction(dataFormat.getDelimiter()));
JavaRDD-stringRdd=rddToWrite.map(新的MyFunction(dataFormat.getDelimiter());
当您访问dataFormat
时,它的意思是this.dataFormat
。
因此spark将尝试序列化此
,并遇到NotSerializableException
尝试制作本地副本,如:
DataFormat dataformat = this.dataformat;
JavaRDD<Row> rddToWrite = dataToWrite.toJavaRDD();
JavaRDD<String> stringRdd = rddToWrite.map(new Function<Row, String>() ...
DataFormat DataFormat=this.DataFormat;
JavaRDD rddToWrite=dataToWrite.toJavaRDD();
JavaRDD stringRdd=rddToWrite.map(新函数()。。。
有关详细信息,请参阅
当您访问
dataFormat
时,它的意思是this.dataFormat
。
因此spark将尝试序列化此
,并遇到NotSerializableException
尝试制作本地副本,如:
DataFormat dataformat = this.dataformat;
JavaRDD<Row> rddToWrite = dataToWrite.toJavaRDD();
JavaRDD<String> stringRdd = rddToWrite.map(new Function<Row, String>() ...
DataFormat DataFormat=this.DataFormat;
JavaRDD rddToWrite=dataToWrite.toJavaRDD();
JavaRDD stringRdd=rddToWrite.map(新函数()。。。
有关详细信息,请参阅
什么是
dataFormat
?是dataFormat
局部变量还是封闭类的字段?什么是dataFormat
?是dataFormat
局部变量还是封闭类的字段?至少在快速测试中,即使是不访问封闭实例的任何方法或字段的匿名类也仍然是如此这是对它的引用,所以我会尝试序列化它。也许我做错了什么,但是…Alexey是对的!这仍然是序列化封闭实例。导致了相同的问题。是的,他是对的。我对java中的匿名函数有一些误解。至少在快速测试中,即使是一个不访问任何方法或域的匿名类封闭实例的ds仍然有对它的引用,因此将尝试序列化它。也许我做错了什么,但是…Alexey是对的!这仍然是序列化封闭实例。导致了相同的问题。是的,他是对的。我对java中的匿名函数有一些误解。