I have a UDF that compares two strings str_left and str_right, but fails if either is a null.
I thought it should be possible to 'protect' the udf with a case expression as follows:
select
case
when str_left is null or str_right is null then -1
else my_udf(str_left, str_right)
end as my_col
from my_table
But this fails in practice. Why does this not work?
Here is a complete example in pyspark, which produces the error TypeError: object of type 'NoneType' has no len() in Spark 2.4.3 and Spark 3.1.2.
from pyspark.context import SparkContext
from pyspark.sql import SparkSession
from pyspark.sql.types import DoubleType
sc = SparkContext.getOrCreate()
spark = SparkSession(sc)
from pyspark.sql import Row
def rel_length(str1, str2):
return len(str1)/len(str2)
spark.udf.register("rel_length_py", rel_length, DoubleType())
rows = [
{"str_col_l": "a string", "str_col_r": "another string"},
{"str_col_l": "a string", "str_col_r": None},
]
df = spark.createDataFrame(Row(**x) for x in rows)
df.createOrReplaceTempView("str_comp")
sql = """select
case
when str_col_r is null or str_col_l is null then -1
else rel_length_py(str_col_l, str_col_r)
end
as rel
from str_comp
"""
spark.sql(sql).show()
I've tried to simplify this down to the reproducible example above. The 'real world' problem we're encountering is a similar case statement with this udf. Here's a gist with the code that produces the error. Strangley, in this more complex example, it fails in spark 3.1.2 but succeeds in 2.4.3.