Spark Scala -使用rlike将DataFrame列转换为时间类型时出错

bvuwiixz  于 5个月前  发布在  Scala
关注(0)|答案(1)|浏览(83)

我在尝试转换存储在Spark DataFrame中的原始时间字符串(hh:mm:ss)时遇到了一个问题,我使用了列类型为“string”的StructType。目标是将这些时间值写入目标列类型为“Time”的关系数据库。

val timeRegex = "(([0-1]?[0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]"
        var convertedData = newData

    newData.schema.fields.foreach { field =>
      val columnName = field.name
      val dataType = field.dataType

      if (dataType == StringType) {
        convertedData = convertedData.withColumn(
          columnName,
          when(expr(s"col($columnName) rlike '$timeRegex'"),
            to_utc_timestamp(substring(col(columnName), 1, 8), "HH:mm:ss").cast("timestamp").cast("time"))
            .otherwise(col(columnName))
        )
      }
    }

字符串
newData是包含我的数据的数据框,time列是hh:mm:ss格式的字符串。然而,当任何字符串(甚至是像“ABCDF_12345”这样的非时间字符串)与timeRegex匹配时就会出现问题。这会导致otherwise块尝试转换为时间戳,从而导致错误。
我正在寻求如何修改代码或改进正则表达式的建议,以确保只有有效的时间字符串被转换,其他字符串保持不变。当前的正则表达式似乎过于宽松,允许非时间字符串匹配。
任何在Spark SQL中实现这种转换的见解或替代方法都将受到极大的赞赏。

qgzx9mmu

qgzx9mmu1#

如果Postgres Time列可以接受Spark Timestamp,则带时间的String字段可以转换为Timestamp;无效时间将转换为null:

val df = Seq("ABCDF_12345", "13:04:22").toDF
val timeRegex = "(([0-1]?[0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]"

val stringFieldNames = df.schema.fields
  .filter(_.dataType == StringType)
  .map(_.name)

def castToTimestamp = (fieldName: String) => when(expr(s"$fieldName rlike '$timeRegex'"), col(fieldName).cast(TimestampType))
val result = stringFieldNames.foldLeft(df)((acc, fieldName) => acc.withColumn(fieldName, castToTimestamp(fieldName)))

字符串
测试结果:

+-------------------+
|value              |
+-------------------+
|null               |
|2023-12-04 13:04:22|
+-------------------+


结果架构:

root
 |-- value: timestamp (nullable = true)

相关问题