I am trying to use an udf defined with Seq[Double] => Seq[Double].
When I am trying to use it with a "raw" array<int> defined at the creation of the Dataframe, Spark does not cast it in array<double> before using my udf.
However, when I generate an array<int> from another udf, Spark casts the column in array<double> before calling my udf.
What is the philosophy behind these casts? What Analyzer's rule is responsible for this cast?
Here some code to illustrate/reproduce:
import org.apache.spark.sql.types._
import org.apache.spark.sql.functions._
import org.apache.spark.sql._
val df = spark.createDataFrame(
spark.sparkContext.parallelize(Seq(Row(Seq(1)))),
StructType(
StructField("array_int", ArrayType(IntegerType, true), false) ::
Nil
)
)
df.show
/**
+---------+
|array_int|
+---------+
| [1]|
+---------+
*/
val f = udf ((v: Seq[Double]) => v)
val generateIntArrays = udf(() => Array.fill(2)(1))
val df1 = df.withColumn("f", f(col("array_int"))) // df1.show fails at runtime, Spark does not cast array_int before calling f
val df2 = df.withColumn("b", generateIntArrays()).withColumn("f", f(col("b"))) // df2.show works at rnutime, Spark explicitly casts the output of col("b") before calling f
df1.explain // not cast
/**
== Physical Plan ==
*(1) Project [array_int#778, UDF(array_int#778) AS f#781]
+- *(1) Scan ExistingRDD[array_int#778]
*/
df2.explain // cast in array<double> before calling `f`
/**
== Physical Plan ==
*(1) Project [array_int#778, UDF() AS b#804, UDF(cast(UDF() as array<double>)) AS f#807]
+- *(1) Scan ExistingRDD[array_int#778]
*/