Scala 时间窗口中的Spark数据帧变换
我有两个数据帧。[AllAccounts]:包含对所有用户的所有帐户的审核Scala 时间窗口中的Spark数据帧变换,scala,apache-spark,spark-dataframe,emr,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:
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中的行。如示例中所示,用户ID 1的acc2在2016-12-06T17:09:38.123-05:00标记为活动,acc3在2016-12-07T17:09:39.123-05:00标记为活动。顺便说一句,这些时间范围acc2将被标记为真,2016-12-07T17:09:39以后的acc3将被标记为真
如果我正确理解帐户
(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)))
val-withFlags=withActive.withColumn(“isActive”,
$“CreatedOn”>=$“StartTime”和
($“EndTime”.isNull | |($“CreatedOn”<$“EndTime)))
您可以编写一个UDF
来执行此操作。