Spark无法找到样例类且代码生成失败问题求助(Scala2.11/Spark2.1.0)
我之前也碰到过几乎一模一样的问题,咱们来拆解下原因和解决办法:
问题根源
你看到的错误Identifier expected instead of '.',核心原因是你的样例类包名里包含了Java的关键字public。Spark的Dataset API在处理样例类时,会自动生成Java代码来完成序列化/反序列化(这也是它比RDD性能更优的原因之一),而Java里public是保留关键字,不能用作包名的一部分,生成的代码行/* 052 */ private com.avro.message.video.public.MetricObservation MapObjects_loopValue34;里的public直接触发了编译错误。
而RDD API能正常运行,是因为RDD依赖的是Scala原生的序列化机制,不需要生成中间Java代码,所以不会碰到这个关键字冲突的问题。
解决方案
1. 重命名包名(推荐)
这是最彻底的解决办法,把包名里的public改成合法的标识符,比如pub、public_metrics或者common之类的。修改后重新编译你的样例类,再用Dataset API处理就不会有问题了,Parquet输出也能正常工作。
2. 临时替代方案(仅应急用,不推荐长期使用)
如果暂时无法修改包名,可以尝试给样例类指定Kryo序列化器,绕开Spark自动生成Java代码的逻辑:
import org.apache.spark.serializer.KryoSerializer // 配置Spark使用Kryo序列化 spark.conf.set("spark.serializer", classOf[KryoSerializer].getName) spark.conf.set("spark.kryo.registrationRequired", "true") spark.conf.set("spark.kryo.classesToRegister", "com.avro.message.video.public.MetricObservation") // 手动指定Encoder创建Dataset import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder val encoder = ExpressionEncoder[com.avro.message.video.public.MetricObservation] val ds = spark.createDataset(data)(encoder)
不过这个方案可能会影响Dataset的性能,后续维护成本也高,还是优先考虑重命名包名。
验证
改完包名后,重新运行流水线,Spark生成的Java代码里就不会出现包含关键字的包名了,编译错误会消失,Dataset也能正常将数据输出为Parquet格式。
内容的提问来源于stack exchange,提问作者Jon

