При попытке преобразовать строки ISO8601 с информацией о часовом поясе в TimestampType с использованием приведения (TimestampType) принимаются только строки с форматом часового пояса +01: 00.Если часовой пояс определен в соответствии со стандартом ISO8601 +0100 (без двоеточия), анализ завершается неудачно и возвращает ноль.Мне нужно преобразовать строку в TimestampType при сохранении части ms.
2019-02-05T14:06:31.556+0100 Returns null
2019-02-05T14:06:31.556+01:00 Returns a correctly parsed TimestampType
Я попытался использовать функции to_timestamp () и unix_timestamp (). Cast (TimestampType).К сожалению, они усекают секцию ms метки времени, которую мне нужно сохранить.Кроме того, вам необходимо применить их к новому столбцу, и вы не сможете выполнить замену атрибута на месте в сложном типе (что возможно, если я сделаю свойство ApiReceived TimestampType в схеме для функции from_json).
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))
Тип вывода указанного выше DataFrame
df:org.apache.spark.sql.DataFrame
Time:string
NewTime:timestamp
NewTime2:timestamp
NewTime3:timestamp
И выходные значения
Time 2019-02-05T14:06:31.556+0100
NewTime 2019-02-05 13:06:31
NewTime2 2019-02-05 13:06:31
NewTime3 null
Есть ли способ заставить 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)
Если вы запустите эти кадры данных и сравните вывод, это несколько уныло.Наиболее приемлемым formatString является второй SSSX
. Единственный разумный способ справиться с этим - UDF, обеспечивающий соответствие всех строк ISO8601 стандарту, который понимает функция, которую вы планируете использовать.
Все еще, не нашли способа сохранить миллисекундную часть в обоих форматах.
2019-02-05T14:06:31.556+01:00 and
2019-02-05T14:06:31.556+0100
Обновление 2
https://issues.apache.org/jira/browse/SPARK-17545?jql=project%20%3D%20SPARK%20AND%20text%20~%20iso8601
Видимо этоНЕ соответствует стандарту ISO8601 для смешивания основных и расширенных форм.Строка «2019-02-05T14: 06: 31.556 + 0100» не в стандартном формате.Тем не менее, это кажется правильным в соответствии с RFC822.
Если я правильно понимаю билет JIRA, стандартный синтаксический анализ (т. Е. Приведение () к строковому столбцу) обрабатывает только правильно отформатированные строки ISO8601, а не RFC822 или другие крайние случаи (т.е. смешивание расширенных и основных форматов).Если у вас есть крайний случай, вы должны предоставить строку формата и использовать другой метод синтаксического анализа.
У меня нет доступа к стандарту ISO8601: 2004, поэтому я не могу проверить, но есть ли комментарий в JIRAправильно интернет нуждается в обновлении.Многие веб-страницы сопоставляют RFC822 и ISO8601 и перечисляют «2019-02-05T14: 06: 31.556 + 0100» в качестве допустимой строки ISO8601.