Spark中链式使用多个.when()条件解析日期时出现异常匹配问题
Spark中链式使用多个.when()条件解析日期时出现异常匹配问题
我来帮你梳理下问题的根源和解决办法:
问题核心原因
- 类型不兼容触发内部错误:你的列是
LongType,但后面几个when条件里的to_timestamp(col(my_col), "格式")重载方法要求输入是StringType。当Spark尝试对Long类型列执行字符串格式的日期解析时,就会触发无法解析表达式的内部错误——它不知道怎么把Long值按字符串日期格式去处理。 - 隐式类型转换引发错误匹配:Spark会隐式把Long转成字符串来执行
rlike匹配,但纯数字的字符串可能会被后面的日期正则意外匹配到(比如某些长数字巧合符合日期正则的结构),导致逻辑走偏。
解决步骤
- 统一转为字符串类型:所有正则匹配和格式解析都基于字符串,先转换类型能彻底避免类型不兼容问题,也能让正则匹配更准确。
- Unix时间戳条件前置:确保纯数字的时间戳先被匹配处理,不会被后面的日期正则误拦截。
- 简化冗余正则:你代码里有重复的
yyyy-MM-dd'T'HH:mm:ss.SSS匹配条件,可以合并成一个,减少冗余。
修正后的代码
from pyspark.sql.types import StringType # 先把Long类型的列转成String类型 str_col = col(my_col).cast(StringType()) parsed_ts = ( when(str_col.rlike(r"^(\d{10,13})(?:\.\d+)?$"), from_unixtime(str_col)) .when(str_col.rlike(r"^\d{4}-\d{2}-\d{2}$"), to_timestamp(str_col, "yyyy-MM-dd")) .when(str_col.rlike(r"^\d{4}/\d{2}/\d{2}$"), to_timestamp(str_col, "yyyy/MM/dd")) .when(str_col.rlike(r"^(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2})(?:\.\d{3})?(?:Z)?$"), to_timestamp(regexp_replace(str_col, r"Z$", ""), "yyyy-MM-dd'T'HH:mm:ss.SSS")) .otherwise(lit(None).cast("timestamp")) ) df = df.withColumn("new_col", parsed_ts)
额外说明
- 我把几个带时分秒的正则合并成了一个:用
[T ]匹配空格或T,(?:\.\d{3})?匹配可选的毫秒部分,(?:Z)?匹配可选的末尾Z,既简化了代码又覆盖了所有对应场景。 - 先转String类型是解决内部错误的关键——Spark再也不用纠结怎么把Long值按字符串日期格式处理了。
- 原来单独处理Unix时间戳没问题,是因为
from_unixtime本身支持Long类型输入,但加了后面的to_timestamp格式解析后,类型冲突就暴露出来了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

