我有两个数据帧。 [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
我想将它们转换为格式为
的单个DFUserId, 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将被标记为真。
这将是一种有效的方法。
答案 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)
请注意,每位用户的最后EndTime
为null
。现在加入:
val withActive = AllAcounts.join(activeTimes, Seq("UserId", "AccountId"))
(如果某些帐户可能缺少活动时间,则应为左连接。)
然后你必须通过并将帐户标记为活动帐户:
val withFlags = withActive.withColumn("isActive",
$"CreatedOn" >= $"StartTime" &&
($"EndTime".isNull || ($"CreatedOn" < $"EndTime)))