首页 > 解决方案 > 用先前的字段值填充 DataFrame 中的空白字段

问题描述

我正在使用 Scala 和 Spark,而且我对 Scala 编程还比较陌生,所以也许我的问题有一个简单的解决方案。

我有一个 DataFrame 在某些促销活动中保留有关活动和停用客户端的信息。该 DataFrame 显示客户 ID、他/她采取的行动(他可以随时激活或停用促销活动)以及他或她采取此行动的日期。这是该格式的示例:

DataFrame 如何工作的示例
DataFrame 如何工作的示例

我希望每天监控活跃的客户,并希望了解这个数字在几天内的变化,但我无法编写任何类似的代码。

我的想法是对两个数据框进行交叉连接;一个只有客户 ID,另一个只有日期,所以我将拥有与所有客户 ID 相关的所有日期,我只需要查看每个日期中的客户状态(如果客户是活动的或非活动的) . 因此,在那之后,我将这些新数据框与与客户端 ID 和事件相关的数据框进行了左连接,但结果是很多日期都处于“空”状态,我不知道如何填充它正确的状态。这是示例:

最终 DataFrame 示例
最终 DataFrame 示例

我已经尝试过使用滞后功能,但它并没有解决我的问题。有没有人有任何可以帮助我的想法?

谢谢你!

标签: scalaapache-spark

解决方案


由于 Spark SQL 对具有 <、<= >、>= 的相关子查询有限制,因此操作成本稍高。

从您的第二个带有 NULL 的数据帧开始,并假设足够大的系统和可管理的数据量:

import org.apache.spark.sql._
import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window

// My sample input
val df  = Seq( 
  (1,"2018-03-12", "activate"),
  (1,"2018-03-13", null),
  (1,"2018-03-14", null),
  (1,"2018-03-15", "deactivate"),
  (1,"2018-03-16", null),
  (1,"2018-03-17", null),
  (1,"2018-03-18", "activate"), 
  (2,"2018-03-13", "activate"), 
  (2,"2018-03-14", "deactivate"), 
  (2,"2018-03-15", "activate") 
 ).toDF("ID", "dt", "act")
//df.show(false)

val w = Window.partitionBy("ID").orderBy(col("dt").asc)
val df2 = df.withColumn("rank", dense_rank().over(w)).select("ID", "dt","act", "rank") //.where("rank == 1")
//df2.show(false)

val df3 = df2.filter($"act".isNull)
//df3.show(false)

val df4 = df2.filter(!($"act".isNull)).toDF("ID2", "dt2", "act2", "rank2")
//df4.show(false)

val df5 = df3.join(df4, (df3("ID") === df4("ID2")) && (df4("rank2") < df3("rank")),"inner") 
//df5.show(false)

val w2 = Window.partitionBy("ID", "rank").orderBy(col("rank2").desc)
val df6 = df5.withColumn("rank_final", dense_rank().over(w2)).where("rank_final == 1").select("ID", "dt","act2").toDF("ID", "dt", "act") 
//df6.show

val df7 = df.filter(!($"act".isNull))

val dfFinal = df6.union(df7)
dfFinal.show(false)

返回:

+---+----------+----------+
|ID |dt        |act       |
+---+----------+----------+
|1  |2018-03-13|activate  |
|1  |2018-03-14|activate  |
|1  |2018-03-16|deactivate|
|1  |2018-03-17|deactivate|
|1  |2018-03-12|activate  |
|1  |2018-03-15|deactivate|
|1  |2018-03-18|activate  |
|2  |2018-03-13|activate  |
|2  |2018-03-14|deactivate|
|2  |2018-03-15|activate  |
+---+----------+----------+

我分步快速地解决了这个问题,但没有那么明显。


推荐阅读