Spark 3.3.0在EKS运行时抛出ClassCastException异常问题
Spark 3.3.0 日期类型转换ClassCastException问题
环境与问题
- 运行环境:Spark 3.3.0、Scala 2.13.5
- 异常表现:Scala代码在本地IntelliJ运行正常,部署到EKS执行时抛出:
Exception in thread "main" java.lang.ClassCastException: java.time.LocalDate cannot be cast to java.sql.Date
代码片段
val listOfDates: List[Date] = cgDatesDf .filter(cgDatesDf("cgDatecol") < lit(bs_date.toString).cast("Date")) .select(col("bs_date")) .collect .map(f => f.getDate(0)) .toList .takeRight(1)
数据集信息
cgDatesDf内容:
+----------------+ |convertedDatecol| +----------------+ | 2016-08-31| | 2016-09-30| | 2016-10-31| | 2021-08-31| | 2021-09-30| | 2021-10-31| | 2021-11-30| | 2021-12-31| | 2022-01-31| | 2022-06-30| +----------------+
其中bs_date值为2021-09-30
问题原因
Spark 3.x 默认采用Java 8的java.time.LocalDate作为DataFrame中Date类型的底层存储实现,但代码中使用的row.getDate(0)是旧API方法,它期望返回java.sql.Date类型,当底层实际存储的是LocalDate时,就会触发类型转换异常。
本地与EKS环境的差异可能源于Spark配置或依赖包的细微区别,导致日期类型的实际存储实现不一致。
解决方案
方案1:正确转换LocalDate为java.sql.Date
直接获取LocalDate类型后转为java.sql.Date,适配Spark 3.x的默认行为:
import java.sql.Date import java.time.LocalDate import org.apache.spark.sql.types.DateType val listOfDates: List[Date] = cgDatesDf .filter(col("cgDatecol") < lit(bs_date).cast(DateType)) // 直接使用DateType,避免字符串转换 .select(col("bs_date")) .collect .map(row => Date.valueOf(row.getAs[LocalDate](0))) // 先获取LocalDate再转为sql.Date .toList .takeRight(1)
方案2:直接使用LocalDate类型
如果业务场景不需要java.sql.Date,可以直接改用LocalDate类型存储结果:
import java.time.LocalDate import org.apache.spark.sql.types.DateType val listOfDates: List[LocalDate] = cgDatesDf .filter(col("cgDatecol") < lit(bs_date).cast(DateType)) .select(col("bs_date")) .collect .map(_.getAs[LocalDate](0)) .toList .takeRight(1)
方案3:调整Spark配置(不推荐)
强制Spark使用旧的日期类型实现,但会失去Java 8日期API的优势,仅作为临时兼容方案:
在SparkSession初始化时添加配置:
val spark = SparkSession.builder() .config("spark.sql.datetime.java8API.enabled", "false") .getOrCreate()
内容的提问来源于stack exchange,提问作者Anand
相关产品推荐
相关产品推荐

