Spark sort与top序列化问题:Task not serializable

前几天在写文章相似度比较,要取每篇文章最长的若干句,然后simHash得相似度。结果问题出现了:

将文章分割成句子之后,无论用sort还是JavaPairRDD的sortByKey方法之后,只要我想拿数据,比如take(int)  ,  top(int)等,都会有一个类似下面的序列化问题出现:

刚开始时用的Lambda表达式,报错是lambda表达式对象无法序列化:

failed in 0.032 s due to Job aborted due to stage failure: Task not serializable: java.io.NotSerializableException: com.tensor.api.org.service.spark.statistics.StatisticsServiceImpl$$Lambda$1054/1846568576
Serialization stack:
	- object not serializable (class: com.tensor.api.org.service.spark.statistics.StatisticsServiceImpl$$Lambda$1054/1846568576, value: com.tensor.api.org.service.spark.statistics.StatisticsServiceImpl$$Lambda$1054/1846568576@41138857)
	- element of array (index: 0)
	- array (class [Ljava.lang.Object;, size 1)
	- field (class: java.lang.invoke.SerializedLambda, name: capturedArgs, type: class [Ljava.lang.Object;)
	- object (class java.lang.invoke.SerializedLambda, SerializedLambda[capturingClass=interface java.util.Comparator, functionalInterfaceMethod=java/util/Comparator.compare:(Ljava/lang/Object;Ljava/lang/Object;)I, implementation=invokeStatic java/util/Comparator.lambda$comparingInt$7b0bb60$1:(Ljava/util/function/ToIntFunction;Ljava/lang/Object;Ljava/lang/Object;)I, instantiatedMethodType=(Ljava/lang/Object;Ljava/lang/Object;)I, numCaptured=1])
...
...
at com.tensor.api.org.service.spark.statistics.StatisticsServiceImpl.getLongestSentences(StatisticsServiceImpl.java:71)
	at SparkServiceTest.main(SparkServiceTest.java:58)

报错里面Lambda表达式后面跟了一串看不懂的数字,根本没法定位问题所在,于是将Lambda表达式全部替换成了函数对象,然后运行:

to Job aborted due to stage failure: Task not serializable: java.io.NotSerializableException: SparkServiceTest$2
Serialization stack:
	- object not serializable (class: SparkServiceTest$2, value: SparkServiceTest$2@2f4daa87)
	- field (class: scala.math.LowPriorityOrderingImplicits$$anon$4, name: cmp$1, type: interface java.util.Comparator)
	- object (class scala.math.LowPriorityOrderingImplicits$$anon$4, scala.math.LowPriorityOrderingImplicits$$anon$4@df3d65d)
	- field (class: scala.math.Ordering$$anon$1, name: $outer, type: interface scala.math.Ordering)
...

这样就清晰很多了,原来是排序时需要传入一个Comparator对象,我们找到Comparator的类定义,发现它并未extends Serializable接口。找到问题就好解决了,只需我们自己写一个SerializableComparator<T>接口去扩展Comparator,在类定义中加上 extends Serializable,然后在使用时传入对象用它替换无法序列化的Comparator就好了。

/**
 * 排序时需要用到{@link Comparator}接口,但它并没有实现序列化,因此总是报错。
 * 在这里给它序列化一下。
 *
 * 没有实现任何方法,仅作为mark interface定义类型
 *
 * 注意,序列化并不是仅仅extends一下接口这么简单,必须十分谨慎,
 * 因为要考虑很多安全、反序列化效率等问题。具体请参见《Effective Java》序列化章节
 * 这里为了赶紧能用,暂时统统省略了
 * 
 * @author lightDance
 */
public interface SerializableComparator<T> extends Comparator<T>, Serializable {
}
mapToPair(new PairFunction<Tuple2<String, Integer>, Integer , String>(){...} , false);

这个问题坑就坑在SparkRDD的lazy机制,虽然是sort这一步出的问题,但报错却报的问题出现在take(),top()这些行动操作上。加上最开始为了简洁用lambda表达式导致无法锁定位置,被这个问题困扰好久。

 

总结一下解决思路:

1.查Spark序列化问题的原因:数据处理流程中使用了无法序列化的对象,特别需要注意有没有对当前类成员的引用,有的话整个类都需要序列化,有时候要配合使用@Transient注解

2.确保当前类引用没问题了,仍然有报错:将链式调用改为逐步处理,锁定报错位置

3.报错中讲Lambda表达式无法序列化,但具体哪一个Lambda表达式有问题,报错中是用一串看不懂的数字表示的:更改Lambda表达式,替换成函数对象

4.锁定是Comparator参数有问题:查看其类定义,发现它未extends Serializable接口,定义子类扩展它,然后使用时参数用自定义子类替换父类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值