Spark时间窗口中的数据帧变换

时间:2018-04-23 21:29:45

标签: scala apache-spark spark-dataframe emr

我有两个数据帧。 [AllAccounts]:包含所有用户的所有帐户的审核

UserId, AccountId, Balance, CreatedOn
1, acc1, 200.01, 2016-12-06T17:09:36.123-05:00
1, acc2, 189.00, 2016-12-06T17:09:38.123-05:00  
1, acc1, 700.01, 2016-12-07T17:09:36.123-05:00
1, acc2, 189.00, 2016-12-07T17:09:38.123-05:00
1, acc3, 010.01, 2016-12-07T17:09:39.123-05:00
1, acc1, 900.01, 2016-12-08T17:09:36.123-05:00

[ActiveAccounts]:仅对任何用户的活动帐户(可能为零或1)进行审核

UserId, AccountId, CreatedOn
1, acc2, 189.00, 2016-12-06T17:09:38.123-05:00
1, acc3, 010.01, 2016-12-07T17:09:39.123-05:00

我想将它们转换为格式为

的单个DF
UserId, AccountId, Balance, CreatedOn, IsActive
1, acc1, 200.01, 2016-12-06T17:09:36.123-05:00, false
1, acc2, 189.00, 2016-12-06T17:09:38.123-05:00, true 
1, acc1, 700.01, 2016-12-07T17:09:36.123-05:00, false
1, acc2, 189.00, 2016-12-07T17:09:38.123-05:00, true
1, acc3, 010.01, 2016-12-07T17:09:39.123-05:00, true
1, acc1, 900.01, 2016-12-08T17:09:36.123-05:00, false

因此,基于ActiveAccounts中的帐户,我需要在第一个df中正确标记行。如示例所示,userId 1的acc2在2016-12-06T17:09:38.123-05:00标记为活动,acc3在2016-12-07T17:09:39.123-05:00标记为活动。所以btw这些时间范围acc2将被标记为真,2016-12-07T17:09:39以后acc3将被标记为真。

这将是一种有效的方法。

1 个答案:

答案 0 :(得分:0)

如果我理解正确,帐户(1, acc1)在其创建时间与(1, acc2)之间有效。

我们可以通过几个步骤完成此操作:

  • 创建一个包含每个帐户的开始/结束时间的数据框
  • 加入AllAccounts
  • 标记结果数据框的行

我还没有对此进行过测试,因此可能存在语法错误。

要完成第一项任务,我们需要按user对数据框进行分区,然后查看下一个创建时间。这需要一个窗口函数:

val window = Window.partitionBy("UserId").orderBy("StartTime")
val activeTimes = ActiveAccounts.withColumnRenamed("CreatedOn", "StartTime")
  .withColumn("EndTime", lead("StartTime") over window)

请注意,每位用户的最后EndTimenull。现在加入:

val withActive = AllAcounts.join(activeTimes, Seq("UserId", "AccountId"))

(如果某些帐户可能缺少活动时间,则应为左连接。)

然后你必须通过并将帐户标记为活动帐户:

val withFlags = withActive.withColumn("isActive",
  $"CreatedOn" >= $"StartTime" && 
 ($"EndTime".isNull || ($"CreatedOn" < $"EndTime)))