我的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 值是否小于或等于常数?
答案 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
期望条件被评估为true
或false
,这是Scala {{ 1}}类型。
此外,UDF不适用于Boolean
数据类型,它可用于Scala对象(Column
,Int
,String
等)
由于您正在使用的是Spark SQL函数,因此您可以像这样重写 UDF :
Boolean
而且,用法是:
val isExpiration = (
when(
abs(datediff(coalesce($"termEnd", $"agrEnd") , $"BCED")) <= 6, lit(0)
).otherwise(lit(1))
)