Spark 4.0.1 读取 JSON 时为什么无法自动推断 date 类型?
Spark 4.0.1 的 JSON reader 不会根据 dateFormat 将字符串自动推断为 DateType。你提供的结果符合它的实现逻辑。如果加载时不能指定 schema,可以先读取 JSON,再用 to_date 转换 d 列。
为什么设置 dateFormat 没有效果?
JSON 未指定 schema 时会自动推断类型,不需要额外设置 inferSchema=true。dateFormat 用于日期类型的解析和格式化,不会让 reader 将符合该格式的字符串识别为日期。示例中的 yyyy-MM-dd 也是该选项的默认值。Spark 4.0.1 JSON 文档
Spark 4.0.1 的 JsonInferSchema.inferField 实现中,字符串处理逻辑包含可选的 Decimal 和 Timestamp 推断,但没有返回 DateType 的分支。因此,开启时间戳推断也不能直接得到所需的 date 类型。Spark 4.0.1 类型推断源码
为什么 CSV 能识别日期?
CSV reader 使用不同的推断规则。启用 inferSchema=true 后,默认开启的 preferDate=true 会尝试将符合 dateFormat 的字符串列推断为日期,示例中的 _c2 因此可以成为 date。preferDate 是 CSV 的选项,不能用来开启 JSON 的日期推断。Spark 4.0.1 CSV 文档
不指定加载 schema,如何转换日期?
读取后,只转换已知具有日期含义的 d 列,其他字段保留自动推断的类型:
import org.apache.spark.sql.functions.{col, to_date}
val raw = spark.read.json("myfile.json")
val result = raw.withColumn(
"d",
to_date(col("d"), "yyyy-MM-dd")
)
result.printSchema()
对于题目提供的数据,转换后的预期 schema 为:
root
|-- d: date (nullable = true)
|-- id: long (nullable = true)
|-- str: string (nullable = true)
to_date 接受日期格式并返回日期值。格式需要传给转换函数,读取阶段的 dateFormat 不会自动传递给它。Spark 日期函数文档
实际数据包含无效日期怎么办?
Spark 4.0.1 默认开启 spark.sql.ansi.enabled。转换无效日期时可能抛出异常,不能一概认为解析失败会返回 null。Spark ANSI 模式说明
对于示例中的 yyyy-MM-dd 日期字符串,如果希望无法转换的值返回 null,可以保留原列,用 try_cast 生成日期列,再找出转换失败的记录:
import org.apache.spark.sql.functions.{col, expr}
val checked = raw.withColumn(
"d_date",
expr("try_cast(d AS DATE)")
)
val invalidDates = checked.filter(
col("d").isNotNull && col("d_date").isNull
)
try_cast 遵循日期类型转换规则,转换失败时返回 null,但不接受自定义日期格式。需要其他格式时,应另行设计解析和异常处理。Spark try_cast 说明
如果无法事先确定日期列名,就需要补充字段约定或业务规则。仅凭字符串看起来像日期,无法可靠判断它是否应该转换为日期。
备注:内容仅供参考。
