【问题标题】:Spark UDF type mismatch errorSpark UDF 类型不匹配错误
【发布时间】:2017-03-07 21:38:06
【问题描述】:

我正在尝试编写一个 UDF 来将时间戳转换为表示一周中的小时的整数。我可以像这样使用 SparkSql 轻松完成此操作。

我的代码中有许多 UDF 使用这种精确的语法,但这个正在尝试类型不匹配错误。我还尝试使用col("session_ts_start") 调用我的UDF,但这也失败了。

import spark.implicits._
import java.sql.Timestamp
import org.apache.spark.sql.functions._

def getHourOfWeek() = udf(
    (ts: Timestamp) => unix_timestamp(ts)
)

val dDF = df.withColumn("hour", getHourOfWeek()(df("session_ts_start")))
dDF.show()

<console>:154: error: type mismatch;
 found   : java.sql.Timestamp
 required: org.apache.spark.sql.Column
           (ts: Timestamp) => unix_timestamp(ts)

【问题讨论】:

    标签: scala apache-spark apache-spark-sql user-defined-functions


    【解决方案1】:

    unix_timestamp 是一个 SQL 函数。它operates on Columns 不是外部值:

    def unix_timestamp(s: Column): Column 
    

    它不能在 UDF 中使用。

    我正在尝试 (...) 将时间戳转换为表示星期几的整数

    import org.apache.spark.sql.Column
    import org.apache.spark.sql.functions.{date_format, hour}
    
    def getHourOfWeek(c: Column) =
      // https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html
      (date_format(c, "u").cast("integer") - 1) * 24 + hour(c)
    
    val df = Seq("2017-03-07 01:00:00").toDF("ts").select($"ts".cast("timestamp"))
    
    df.select(getHourOfWeek($"ts").alias("hour")).show
    
    +----+
    |hour|
    +----+
    |  25|
    +----+
    

    另一种可能的解决方案:

    import org.apache.spark.sql.functions.{next_day, date_sub}
    
    def getHourOfWeek2(c: Column) = ((
      c.cast("bigint") - 
      date_sub(next_day(c, "Mon"), 7).cast("timestamp").cast("bigint")
    ) / 3600).cast("int")
    
    df.select(getHourOfWeek2($"ts").alias("hour"))
    
    +----+
    |hour|
    +----+
    |  25|
    +----+
    

    注意:两种解决方案都不能处理夏令时或其他日期/时间细节。

    【讨论】:

      猜你喜欢
      • 2018-07-15
      • 2020-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-16
      相关资源
      最近更新 更多