Это, вероятно, проще всего объяснить на примере. Предположим, у меня есть DataFrame для входа пользователя на сайт, например:
scala> df.show(5)
+----------------+----------+
| user_name|login_date|
+----------------+----------+
|SirChillingtonIV|2012-01-04|
|Booooooo99900098|2012-01-04|
|Booooooo99900098|2012-01-06|
| OprahWinfreyJr|2012-01-10|
|SirChillingtonIV|2012-01-11|
+----------------+----------+
only showing top 5 rows
Я хотел бы добавить к этому столбец, указывающий, когда они стали активным пользователем на сайте. Но есть одно предостережение: есть период времени, в течение которого пользователь считается активным, и по истечении этого периода, если они снова became_active в систему, они будут became_active. Предположим, что этот период составляет 5 дней. Тогда желаемая таблица, полученная из приведенной выше таблицы, будет примерно такой:
+----------------+----------+-------------+
| user_name|login_date|became_active|
+----------------+----------+-------------+
|SirChillingtonIV|2012-01-04| 2012-01-04|
|Booooooo99900098|2012-01-04| 2012-01-04|
|Booooooo99900098|2012-01-06| 2012-01-04|
| OprahWinfreyJr|2012-01-10| 2012-01-10|
|SirChillingtonIV|2012-01-11| 2012-01-11|
+----------------+----------+-------------+
Так, в частности, SirChillingtonIV стала became_active дата была сброшена, потому что их второй логин пришел после истечения активного периода, но Booooooo99900098 became_active date не был сброшен во второй раз, когда он/она вошел в систему, потому что он попал в активный период.
Моя первоначальная мысль заключалась в том, чтобы использовать функции окна с lag, а затем использовать значения lag для заполнения столбца became_active; например, что-то началось примерно так:
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
val window = Window.partitionBy("user_name").orderBy("login_date")
val df2 = df.withColumn("tmp", lag("login_date", 1).over(window))
Тогда правилом, чтобы заполнить дату became_active было бы, если tmp равно null (т. login_date - tmp >= 5 Если это первый когда-либо логин), или если login_date - tmp >= 5 то became_active = login_date; в противном случае перейдите к следующему последнему значению в tmp и примените одно и то же правило. Это говорит о рекурсивном подходе, в котором я испытываю трудности с созданием способа реализации.
Мои вопросы: Является ли это жизнеспособным подходом, и если да, то как я могу "вернуться" и посмотреть на более ранние значения tmp пока не найду ту, где останавливаюсь? Я не могу, насколько мне известно, перебирать значения Column Spark SQL. Есть ли другой способ достичь этого результата?