我的SparkDataDrame中有一个日期列,其中包含多种字符串格式。我想将它们投射到DateTime。
DataDrame
我的专栏中的两种格式是:
mm/dd/yyyy
yyyy-mm-dd
到目前为止,我的解决方案是使用UDF更改第一个日期格式以匹配第二个日期,如下所示:
import re def parseDate(dateString): if re.match('\d{1,2}\/\d{1,2}\/\d{4}', dateString) is not None: return datetime.strptime(dateString, '%M/%d/%Y').strftime('%Y-%M-%d') else: return dateString # Create Spark UDF based on above function dateUdf = udf(parseDate) df = (df.select(to_date(dateUdf(raw_transactions_df['trans_dt']))))
这行得通,但并不是所有的容错功能。我特别关注:
dd/mm/yyyy
有一个更好的方法吗?
我个人建议直接使用SQL函数,而不必进行昂贵且效率低的重新格式化:
from pyspark.sql.functions import coalesce, to_date def to_date_(col, formats=("MM/dd/yyyy", "yyyy-MM-dd")): # Spark 2.2 or later syntax, for < 2.2 use unix_timestamp and cast return coalesce(*[to_date(col, f) for f in formats])
这将选择第一种格式,该格式可以成功解析输入字符串。
用法:
df = spark.createDataFrame([(1, "01/22/2010"), (2, "2018-12-01")], ("id", "dt")) df.withColumn("pdt", to_date_("dt")).show() +---+----------+----------+ | id| dt| pdt| +---+----------+----------+ | 1|01/22/2010|2010-01-22| | 2|2018-12-01|2018-12-01| +---+----------+----------+
速度比快udf,添加新格式仅是调整formats参数的问题。
udf
formats
但是,它不会帮助您解决格式歧义问题。在一般情况下,如果没有人工干预和与外部数据的交叉引用,可能无法做到这一点。
当然可以在Scala中完成同一件事:
import org.apache.spark.sql.Column import org.apache.spark.sql.functions.{coalesce, to_date} def to_date_(col: Column, formats: Seq[String] = Seq("MM/dd/yyyy", "yyyy-MM-dd")) = { coalesce(formats.map(f => to_date(col, f)): _*) }