Spark Scala使用rlike转换DataFrame列至时间类型报错求助
解决Spark DataFrame字符串转Time类型的匹配错误问题
问题根源
你当前的正则表达式没有锚定字符串的开头和结尾,导致只要字符串中包含任意一段符合hh:mm:ss格式的子串,就会被误判为有效时间,进而触发转换报错。比如像"ABCDF_12345"这类字符串,会因正则的宽松匹配逻辑被误判,进入转换流程后引发错误。
解决方案
1. 修正正则表达式
添加^(字符串开头)和$(字符串结尾)锚点,确保整个字符串严格匹配hh:mm:ss格式:
val timeRegex = "^(([0-1]?[0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]$"
这个正则会严格校验:
- 小时:0-19(1位或2位)或20-23
- 分钟/秒:00-59
- 整个字符串仅包含有效时间格式,无多余字符
2. 优化转换代码
去掉不必要的substring(正则已确保整个字符串是有效时间),简化转换逻辑:
var convertedData = newData val timeRegex = "^(([0-1]?[0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]$" newData.schema.fields.foreach { field => val columnName = field.name if (field.dataType == StringType) { convertedData = convertedData.withColumn( columnName, when(col(columnName).rlike(timeRegex), // 先转成timestamp,再强制转换为time类型 to_timestamp(col(columnName), "HH:mm:ss").cast("time") ).otherwise(col(columnName)) ) } }
3. 更高效的针对性处理(可选)
如果你明确知道哪些列是时间列,直接针对这些列处理,避免遍历所有字符串列,提升性能:
// 替换为实际的时间列名称列表 val targetTimeColumns = List("login_time", "operation_time") val timeRegex = "^(([0-1]?[0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9]$" var convertedData = newData targetTimeColumns.foreach { colName => convertedData = convertedData.withColumn( colName, when(col(colName).rlike(timeRegex), to_timestamp(col(colName), "HH:mm:ss").cast("time") ).otherwise(col(colName)) ) }
4. 增强容错的try_cast方案(可选)
如果担心正则仍有遗漏,可以结合try_cast避免转换失败报错,失败时返回原字符串:
convertedData = convertedData.withColumn( columnName, when(col(columnName).rlike(timeRegex), try_cast(to_timestamp(col(columnName), "HH:mm:ss").cast("time")) ).otherwise(col(columnName)) )
内容的提问来源于stack exchange,提问作者QueryQuasar
相关产品推荐
相关产品推荐

