Mol*_*tch 6 apache-spark databricks azure-databricks
当尝试使用cast(TimestampType)将具有时区信息的ISO8601字符串转换为TimestampType时,仅接受时区格式为+01:00的字符串。如果以ISO8601合法方式+0100(不含冒号)定义了时区,则解析将失败并返回null。我需要在保留ms部分的同时将字符串转换为TimestampType。
2019-02-05T14:06:31.556+0100 Returns null
2019-02-05T14:06:31.556+01:00 Returns a correctly parsed TimestampType
Run Code Online (Sandbox Code Playgroud)
我试图使用to_timestamp()和unix_timestamp()。cast(TimestampType)函数。不幸的是,它们截断了我需要保留的时间戳的ms部分。另外,您需要将它们应用于新列,并且不能就地替换复杂类型中的属性(如果我在from_json函数的模式中将ApiReceived属性设为TimestampType,则可以这样做)。
df
.select($"body".cast(StringType))
.select(from_json($"body", schema).as("Payload"))
.select($"Payload.Metadata.ApiReceived".as("Time"))
.withColumn("NewTime", to_timestamp($"Time", "yyyy-MM-dd'T'HH:mm:ss.SSSZ"))
.withColumn("NewTime2", unix_timestamp($"Time", "yyyy-MM-dd'T'HH:mm:ss.SSSZ").cast(TimestampType))
.withColumn("NewTime3", $"Time".cast(TimestampType))
Run Code Online (Sandbox Code Playgroud)
上面的DataFrame的输出类型
df:org.apache.spark.sql.DataFrame
Time:string
NewTime:timestamp
NewTime2:timestamp
NewTime3:timestamp
Run Code Online (Sandbox Code Playgroud)
并输出值
Time 2019-02-05T14:06:31.556+0100
NewTime 2019-02-05 13:06:31
NewTime2 2019-02-05 13:06:31
NewTime3 null
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以使Spark在不依靠UDF:s的情况下处理转换?
更新资料
经过更彻底的调查后,我发现Sparks日期时间解析有些不一致。:)
val df = Seq(
//Extended format
("2019-02-05T14:06:31.556+01:00"),
("2019-02-05T14:06:31.556+01"),
("2019-02-05T14:06:31.556"),
//Basic Format
("20190205T140631556+0100"),
("20190205T140631556+01"),
("20190205T140631556"),
//Mixed extended with basic
("2019-02-05T14:06:31.556+0100"),
("20190205T140631556+01:00")
).toDF
val formatStrings = Seq(
("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
("yyyy-MM-dd'T'HH:mm:ss.SSSX"),
("yyyyMMdd'T'HHmmssSSSZ"),
("yyyyMMdd'T'HHmmssSSSX")
)
val format = formatStrings(0)
val df2 = df
.select($"value".as("Time"))
.withColumn("NewTime3", $"Time".cast(TimestampType))
.withColumn("NewTime", to_timestamp($"Time", format))
.withColumn("NewTime2", unix_timestamp($"Time", format).cast(TimestampType))
.withColumn("NewTime4", date_format($"Time", format))
display(df2)
Run Code Online (Sandbox Code Playgroud)
我运行这些数据帧并比较输出,这有些令人沮丧。最宽松的formatString是第二个SSSX
解决此问题的唯一合理方法是UDF,该UDF确保所有ISO8601字符串均符合计划使用的功能可以理解的标准。
不过,还没有找到一种在两种格式下都保留毫秒部分的方法。
2019-02-05T14:06:31.556+01:00 and
2019-02-05T14:06:31.556+0100
Run Code Online (Sandbox Code Playgroud)
更新2
显然,不符合ISO8601标准的混合基本形式和扩展形式。字符串“ 2019-02-05T14:06:31.556 + 0100”不是标准格式。不过,根据RFC822,这似乎是正确的。
如果我正确理解JIRA票证,则标准解析(即字符串列上的cast())只会处理格式正确的ISO8601字符串,而不处理RFC822或其他边缘情况(即混合扩展格式和基本格式)。如果您使用的是小写字母,则必须提供格式字符串并使用其他解析方法。
我没有访问ISO8601:2004标准的权限,所以我无法检查,但是JIRA中的注释正确无误,因此互联网需要更新。许多网页将RFC822和ISO8601合并在一起,并将“ 2019-02-05T14:06:31.556 + 0100”列为合法的ISO8601字符串。
| 归档时间: |
|
| 查看次数: |
526 次 |
| 最近记录: |