Scala Spark SQL-如何将RelationalGroupedDataSet转换为DataFrame

Scala Spark SQL-如何将RelationalGroupedDataSet转换为DataFrame,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,嗨 在我的问题中,我需要对数据帧进行分组,为每个组应用业务逻辑,并最终在此基础上发出一个新的数据帧。为了详细描述,有一个设备\u数据帧,其中包含设备打开(打开)和关闭(关闭)的时间戳 +-----------+------+--------------------+ |设备| id |状态| d|ts| +---------+----- +--------------------+ |1 | on | 2020-09-01 16:14:58| |1 | off | 2020-09-1016:14

在我的问题中,我需要对数据帧进行分组,为每个组应用业务逻辑,并最终在此基础上发出一个新的数据帧。为了详细描述,有一个
设备\u数据帧
,其中包含设备打开(
打开
)和关闭(
关闭
)的时间戳

+-----------+------+--------------------+
|设备| id |状态| d|ts|
+---------+----- +--------------------+
|1 | on | 2020-09-01 16:14:58|
|1 | off | 2020-09-1016:14:58|
|1 | on | 2020-09-19 16:14:58|
|2 | on | 2020-09-20 16:14:58|
|2 | off | 2020-10-03 16:14:58|
|4 | on | 2020-09-20 16:14:58|
|5 | off | 2020-09-20 16:14:58|
+---------+-----+-------+-------------+
另一方面,存在包含事件信息的数据帧,包括其时间戳及其对应的设备

+-----+---------+--------------------+
|e|u id |设备| e|ts|
+-----+---------+--------------------+
|1    |1        |2020-09-20 16:14:58 |
|2    |2        |2020-10-08 09:19:55 |
|3    |4        |2020-11-01 12:15:37 |
|4    |5        |2020-10-08 01:35:08 |
+-----+---------+-------+------------+
以下是两个数据帧的联接示例:

+---------+-----+--------------------+------+--------------------+
|设备id | e|u id | e|u ts |状态| d|ts|
+---------+-----+--------------------+------+--------------------+
|1 | 1 | 2020-09-20 16:14:58 | on | 2020-09-01 16:14:58|
|1 | 1 | 2020-09-20 16:14:58 | off | 2020-09-10 16:14:58|
|1 | 1 | 2020-09-20 16:14:58 | on | 2020-09-19 16:14:58|
|2 | 2 | 2020-10-08 09:19:55 | on | 2020-09-20 16:14:58|
|2 | 2 | 2020-10-08 09:19:55 | off | 2020-10-03 16:14:58|
|4 | 3 | 2020-11-01 12:15:37 | on | 2020-09-20 16:14:58|
|5 | 4 | 2020-10-08 01:35:08 | off | 2020-09-20 16:14:58|
+---------+-----+-------+--------------------+------+------------+
我最后需要找到的是当其相应设备处于
开启状态时发生的事件信息。例如,在上表的情况下,事件id
1
是有效的,因为它发生在
2020-09-20 16:14:58
上,并且其设备自
2020-09-19 16:14:58
以来一直处于
开启状态,事件id
2
无效,因为其设备已关闭
2020-10-03 16:14:58
且从未再次打开,依此类推

Update1:我需要的另一个信息是事件发生前设备被设置为
on
的次数,结果如下表所示:

+---------+-----+----------+-------------------+
|设备| e | id | on | u count | e | ts|
+---------+-----+----------+-------------------+
|1        |1    |    2     |2020-09-20 16:14:58|
|4        |3    |    1     |2020-11-01 12:15:37|
+---------+-----+----------+-------------------+
在上表中,事件id
1
on\u count
值为2,因为当它发生在
2020-09-20 16:14:58
时,设备id
1
已开启两次

我根据设备对联接表进行了以下分组:

val group=eventDF
.join(deviceDF,“设备id”)
.groupBy(“设备id”)
这将导致
RelationalGroupedDataSet
。现在我需要将逻辑应用到每个组并发出结果数据帧,但我没有找到解决方案。我检查了
UDAF
s,但发现它在我的案例中不起作用

我知道如何使用RDDAPI解决这个问题,但我想找到它的列API方法。 任何帮助或建议都将不胜感激


谢谢

您可以使用下面的逻辑获取每个
设备\u id
的最后状态,并过滤最后状态为
的行

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

val result = eventDF
    .join(deviceDF, "device_id")
    .withColumn(
        "last_state",
        max(when($"d_ts" < $"e_ts", array($"d_ts", $"state"))).over(Window.partitionBy("device_id", "e_id"))(1)
    )
    .withColumn(
        "on_count",
        count(when($"state" === "on" && $"d_ts" < $"e_ts", 1)).over(Window.partitionBy("device_id", "e_id"))
    )
    .filter("last_state = 'on'")
    .select("device_id", "e_id", "on_count", "e_ts")
    .distinct

result.show
+---------+----+--------+-------------------+
|device_id|e_id|on_count|               e_ts|
+---------+----+--------+-------------------+
|        1|   1|       2|2020-09-20 16:14:58|
|        4|   3|       1|2020-11-01 12:15:37|
+---------+----+--------+-------------------+
import org.apache.spark.sql.expressions.Window
val结果=eventDF
.join(deviceDF,“设备id”)
.withColumn(
“最后的州”,
最大值(当($“d_ts”<$“e_ts”、数组($“d_ts”、$“状态”))。超过(Window.partitionBy(“设备id”、“e_id”)))(1)
)
.withColumn(
“按计数”,
计数(当($“state”==“on”&&&$“d_ts”<$“e_ts”,1))超过(Window.partitionBy(“设备id”,“e_id”))
)
.filter(“上一个_状态='on'”)
.选择(“设备id”、“e\U id”、“计数”、“e\U ts”)
不同的
结果显示
+---------+----+--------+-------------------+
|设备| e | id | on | u count | e | ts|
+---------+----+--------+-------------------+
|        1|   1|       2|2020-09-20 16:14:58|
|        4|   3|       1|2020-11-01 12:15:37|
+---------+----+--------+-------------------+

方法不错,谢谢。我还需要知道每个有效事件发生时设备被打开(
打开
)的次数。我用所需的输出更新了我的问题,对于事件1和3,
on_count
值分别为2和1(这意味着,例如,当事件1发生时,设备已设置为
on
两次)@SoheilPourbafrani检查编辑的答案?似乎您考虑了
设备id
的每个分区中的
上的所有
,但我们只需要考虑每个分区中事件发生之前发生的
上的
。@SoheilPourbafrani在计数中添加了另一个条件。“这样可以吗?”SoheilPourbafrani试着回答?您还可以通过
e_id
进行分区。