Suppose I have a dataframe like this.
val df = sc.parallelize(Seq(
(1.0, 1,"Matt"),
(1.0, 2,"John"),
(1.0, 3,null.asInstanceOf[String]),
(-1.0, 2,"Adam"),
(-1.0, 4,"Steve"))
).toDF("id", "timestamp","name")
I want to get the last non-null value for each id ordered by timestamp. This is my window
val partitionWindow = Window.partitionBy($"id").orderBy($"timestamp".desc)
I am creating a distinct windowed data
val filteredDF = df.filter($"name".isNotNull).withColumn("firstName", first("name") over (partitionWindow)).drop("timestamp","name").distinct
and joining it back to the actual data
val joinedDF = df.join(filteredDF, windowDF.col("id") === filteredDF.col("id")).drop(filteredDF.col("id"))
joinedDF.show()
It works fine, but I dont like this solution, can anyone suggest me something better?
Also, can anyone tell me why does last function not work? I tried this and the results are not correct
val partitionWindow = Window.partitionBy($"id").orderBy($"timestamp")
val windowDF = df.withColumn("lastName", last("name") over (partitionWindow))
If you want to propagate the last known value (it is not the same as logic used with join) you should:
ORDER BY timestamp.last ignoring nulls:val partitionWindow = Window.partitionBy($"id").orderBy($"timestamp")
df.withColumn("lastName", last("name", true) over (partitionWindow)).show
// +----+---------+-----+--------+
// | id|timestamp| name|lastName|
// +----+---------+-----+--------+
// |-1.0| 2| Adam| Adam|
// |-1.0| 4|Steve| Steve|
// | 1.0| 1| Matt| Matt|
// | 1.0| 2| John| John|
// | 1.0| 3| null| John|
// +----+---------+-----+--------+
If you want to take the last value globally:
ORDER BY timestamp.last ignoring nulls:val partitionWindow = Window.partitionBy($"id").orderBy($"timestamp")
.rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)
df.withColumn("lastName", last("name", true) over (partitionWindow)).show
// +----+---------+-----+--------+
// | id|timestamp| name|lastName|
// +----+---------+-----+--------+
// |-1.0| 2| Adam| Steve|
// |-1.0| 4|Steve| Steve|
// | 1.0| 1| Matt| John|
// | 1.0| 2| John| John|
// | 1.0| 3| null| John|
// +----+---------+-----+--------+
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With