使用窗口对scala 2中具有if条件的行进行计数
我已经发布了一个类似的问题,但是有人给了我一个技巧来避免使用“if条件” 在这里,我处于一个类似的位置,我没有找到任何技巧来避免它 我有一个数据帧使用窗口对scala 2中具有if条件的行进行计数,scala,apache-spark,Scala,Apache Spark,我已经发布了一个类似的问题,但是有人给了我一个技巧来避免使用“if条件” 在这里,我处于一个类似的位置,我没有找到任何技巧来避免它 我有一个数据帧 var df = sc.parallelize(Array( (1, "2017-06-29 10:53:53.0","2017-06-25 14:60:53.0","boulanger.fr"), (2, "2017-07-05 10:48:57.0","2017-09-05 08:60:53.0","patissier.fr"), (3,
var df = sc.parallelize(Array(
(1, "2017-06-29 10:53:53.0","2017-06-25 14:60:53.0","boulanger.fr"),
(2, "2017-07-05 10:48:57.0","2017-09-05 08:60:53.0","patissier.fr"),
(3, "2017-06-28 10:31:42.0","2017-02-28 20:31:42.0","boulanger.fr"),
(4, "2017-08-21 17:31:12.0","2017-10-21 10:29:12.0","patissier.fr"),
(5, "2017-07-28 11:22:42.0","2017-05-28 11:22:42.0","boulanger.fr"),
(6, "2017-08-23 17:03:43.0","2017-07-23 09:03:43.0","patissier.fr"),
(7, "2017-08-24 16:08:07.0","2017-08-22 16:08:07.0","boulanger.fr"),
(8, "2017-08-31 17:20:43.0","2017-05-22 17:05:43.0","patissier.fr"),
(9, "2017-09-04 14:35:38.0","2017-07-04 07:30:25.0","boulanger.fr"),
(10, "2017-09-07 15:10:34.0","2017-07-29 12:10:34.0","patissier.fr"))).toDF("id", "date1","date2", "mail")
df = df.withColumn("date1", (unix_timestamp($"date1", "yyyy-MM-dd HH:mm:ss").cast("timestamp")))
df = df.withColumn("date2", (unix_timestamp($"date2", "yyyy-MM-dd HH:mm:ss").cast("timestamp")))
df = df.orderBy("date1", "date2")
它看起来像:
+---+---------------------+---------------------+------------+
|id |date1 |date2 |mail |
+---+---------------------+---------------------+------------+
|3 |2017-06-28 10:31:42.0|2017-02-28 20:31:42.0|boulanger.fr|
|1 |2017-06-29 10:53:53.0|2017-06-25 15:00:53.0|boulanger.fr|
|2 |2017-07-05 10:48:57.0|2017-09-05 09:00:53.0|patissier.fr|
|5 |2017-07-28 11:22:42.0|2017-05-28 11:22:42.0|boulanger.fr|
|4 |2017-08-21 17:31:12.0|2017-10-21 10:29:12.0|patissier.fr|
|6 |2017-08-23 17:03:43.0|2017-07-23 09:03:43.0|patissier.fr|
|7 |2017-08-24 16:08:07.0|2017-08-22 16:08:07.0|boulanger.fr|
|8 |2017-08-31 17:20:43.0|2017-05-22 17:05:43.0|patissier.fr|
|9 |2017-09-04 14:35:38.0|2017-07-04 07:30:25.0|boulanger.fr|
|10 |2017-09-07 15:10:34.0|2017-07-29 12:10:34.0|patissier.fr|
+---+---------------------+---------------------+------------+
对于每个id,我想在所有其他行中计算具有以下内容的行数:
val w = Window.partitionBy("mail").orderBy(col("date1").cast("long")).rangeBetween(-60*24*60*60,-1*24*60*60)
var df= df.withColumn("all_previous", count("mail") over w)
但这将对条件1和条件3作出反应,但不会对第二个条件作出反应。。。我必须添加一些东西来包含第二个条件,将date2与我的_date1进行比较…使用一个通用的窗口规范,
last(date1)
是每个窗口分区的当前date1
,以及一个超过0和1的和作为条件计数,以下是我如何将您的条件#2纳入计数标准:
import org.apache.spark.sql.functions._
import org.apache.spark.sql.expressions.Window
def days(n: Long): Long = n * 24 * 60 * 60
val w = Window.partitionBy("mail").orderBy($"date1".cast("long"))
val w1 = w.rangeBetween(days(-60), days(0))
val w2 = w.rangeBetween(days(-60), days(-1))
df.withColumn("all_previous", sum(
when($"date2".cast("long") < last($"date1").over(w1).cast("long"), 1).
otherwise(0)
).over(w2)
).na.fill(0).
show
// +---+-------------------+-------------------+------------+------------+
// | id| date1| date2| mail|all_previous|
// +---+-------------------+-------------------+------------+------------+
// | 3|2017-06-28 10:31:42|2017-02-28 20:31:42|boulanger.fr| 0|
// | 1|2017-06-29 10:53:53|2017-06-25 15:00:53|boulanger.fr| 1|
// | 5|2017-07-28 11:22:42|2017-05-28 11:22:42|boulanger.fr| 2|
// | 7|2017-08-24 16:08:07|2017-08-22 16:08:07|boulanger.fr| 3|
// | 9|2017-09-04 14:35:38|2017-07-04 07:30:25|boulanger.fr| 2|
// | 2|2017-07-05 10:48:57|2017-09-05 09:00:53|patissier.fr| 0|
// | 4|2017-08-21 17:31:12|2017-10-21 10:29:12|patissier.fr| 0|
// | 6|2017-08-23 17:03:43|2017-07-23 09:03:43|patissier.fr| 0|
// | 8|2017-08-31 17:20:43|2017-05-22 17:05:43|patissier.fr| 1|
// | 10|2017-09-07 15:10:34|2017-07-29 12:10:34|patissier.fr| 2|
// +---+-------------------+-------------------+------------+------------+
import org.apache.spark.sql.functions_
导入org.apache.spark.sql.expressions.Window
定义天数(n:长):长=n*24*60*60
val w=Window.partitionBy(“邮件”).orderBy($“date1.cast(“long”))
val w1=w.范围介于(天(-60),天(0))
val w2=w.范围介于(天(-60),天(-1))
df.带列(“所有之前”,总和(
当($“date2.cast”(“long”)
[更新]
此解决方案不正确,即使示例数据集的结果似乎正确。特别是,last($“date1”)。over(w1)
没有按预期的方式工作。答案有望成为有效解决方案的线索。@Biswanath如果你有这个窍门的话…:-)我想也许自定义聚合函数可以解决您的问题。但是自定义聚合是无状态的。它们没有保持在第二种情况下计算所需的状态。我不理解2窗口的用法。我想做的是:val w2=Window.partitionBy(“mail”).orderBy($“date1.cast”(“long”).rangeBetween(days(-60),days(-1))var df2=df.withColumn(“all_previous”),sum(when($“date2.cast”(“long”)
有人理解它为什么不起作用吗?这里是我通过这样做得到的错误信息:org.apache.spark.sql.catalyst.trees.TreeNode.foreach(TreeNode.scala:118)org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$foreach$1.apply(TreeNode.scala:119)在org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$foreach$1.apply(TreeNode.scala:119)的scala.collection.immutable.List.foreach(List.scala:381)
@Anneso,我看到两个问题:1。您的sum()
覆盖了整个数据帧,2last()
在范围内
-受限窗口将不包括“当前行”。谢谢,这对我来说更清楚了。然而,我得到了一个似乎不起作用的例子。。。我把它作为一个新的答案,以便有机会以一种可读的方式来做它(评论并不容易:)@anne所以,我的解决方案是不正确的。我在这一点上没有有效的解决方案,因此您可能想要取消接受答案。