比较语法错误较小或相等

时间:2018-06-28 07:32:05

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

我的UDF正在比较两列之间的时间差是否在5天以内。如果使用==运算符,则表达式可以正确编译,但<=(或lt)将失败,并出现类型不匹配错误。代码:

val isExpiration : (Column, Column, Column) =>
Column = (BCED, termEnd, agrEnd) =>
{
   if(abs(datediff(if(termEnd == null) {agrEnd} else {termEnd}, BCED)) lt 6)
      {lit(0)}
else
      {lit(1)}
}

错误:

notebook:3: error: type mismatch;
 found   : org.apache.spark.sql.Column
 required: Boolean
    if(abs(datediff(if(termEnd == null) {agrEnd} else {termEnd}, BCED)) lt 6) {lit(0)}...
                                                                        ^

我必须缺少明显的东西-谁能建议如何测试 Column 值是否小于或等于常数?

2 个答案:

答案 0 :(得分:2)

似乎您混合使用了udf和Spark函数,您只需要使用其中之一即可。在可能的情况下,最好使用 not udf,因为它们无法优化(因此通常较慢)。如果没有udf,则可以按照以下步骤进行操作:

df.withColumn("end", when($"termEnd".isNull, $"agrEnd").otherwise($"termEnd"))
  .withColumn("expired", when(abs(datediff($"end", $"BCED")) lt 6, 0).otherwise(1))

我引入了一个临时列,以使代码更具可读性。


例如,可以使用udf进行以下操作:

val isExpired = udf((a: Date, b: Date) => {
  if ((math.abs(a.getTime() - b.getTime()) / (1000 * 3600 * 24)) < 6) { 
    0
  } else { 
    1
  }
})

df.withColumn("end", when($"termEnd".isNull, $"agrEnd").otherwise($"termEnd"))
  .withColumn("expired", isExpired($"end", $"BCED"))

在这里,我再次使用了一个临时列,但是如果愿意,可以将此逻辑移到udf中。

答案 1 :(得分:2)

这是因为abs(col).lt(6)返回类型为Column的对象,并且if期望条件被评估为truefalse,这是Scala {{ 1}}类型。

此外,UDF不适用于Boolean数据类型,它可用于Scala对象(ColumnIntString等)

由于您正在使用的是Spark SQL函数,因此您可以像这样重写 UDF

Boolean

而且,用法是:

val isExpiration = (
    when(
        abs(datediff(coalesce($"termEnd", $"agrEnd") , $"BCED")) <= 6, lit(0)
    ).otherwise(lit(1))
)