在不知道执行开始的情况下运行时计算

时间:2017-09-06 11:31:23

标签: scala apache-spark

我想计算多个录像机的运行时间。可以有无限刻录机同时运行。

当我有一个起点和终点时,我会使用以下代码片段获得预期结果。

val ds2 = ds
      .withColumn("started", when($"status" === "start", 1).otherwise(lit(0)))
      .withColumn("stopped", when($"status" === "stop", -1).otherwise(lit(0)))
      .withColumn("engFlag", when($"started" === 1, $"started").otherwise($"stopped"))
      .withColumn("engWindow", sum($"engFlag").over(Window.orderBy($"timestamp")))
      .withColumn("runtime", when($"engWindow" > 0,
        (unix_timestamp(lead($"timestamp", 1).over(Window.orderBy($"timestamp"))) - unix_timestamp($"timestamp"))/60*$"engWindow").otherwise(lit(0)))  

输入数据:

val ds_working = spark.sparkContext.parallelize(Seq(
      ("2017-01-01 06:00:00", "start", "1"),
      ("2017-01-01 07:00:00", "start", "2"),
      ("2017-01-01 08:00:00", "foo", "2"),
      ("2017-01-01 09:00:00", "blub", "2"),
      ("2017-01-01 10:00:00", "stop", "3"),
      ("2017-01-01 11:00:00", null, "3"),
      ("2017-01-01 12:00:00", "ASC_c", "4"),
      ("2017-01-01 13:00:00", "stop", "5" ),
      ("2017-01-01 14:00:00", null, "3"),
      ("2017-01-01 15:00:00", "ASC_c", "4")
    )).toDF("timestamp", "status", "msg")

输出:

+-------------------+------+---+-------+-------+-------+---------+-------+
|          timestamp|status|msg|started|stopped|engFlag|engWindow|runtime|
+-------------------+------+---+-------+-------+-------+---------+-------+
|2017-01-01 06:00:00| start|  1|      1|      0|      1|        1|   60.0|
|2017-01-01 07:00:00| start|  2|      1|      0|      1|        2|  120.0|
|2017-01-01 08:00:00|   foo|  2|      0|      0|      0|        2|  120.0|
|2017-01-01 09:00:00|  blub|  2|      0|      0|      0|        2|  120.0|
|2017-01-01 10:00:00|  stop|  3|      0|     -1|     -1|        1|   60.0|
|2017-01-01 11:00:00|  null|  3|      0|      0|      0|        1|   60.0|
|2017-01-01 12:00:00| ASC_c|  4|      0|      0|      0|        1|   60.0|
|2017-01-01 13:00:00|  stop|  5|      0|     -1|     -1|        0|    0.0|
|2017-01-01 14:00:00|  null|  3|      0|      0|      0|        0|    0.0|
|2017-01-01 15:00:00| ASC_c|  4|      0|      0|      0|        0|    0.0|
+-------------------+------+---+-------+-------+-------+---------+-------+

现在我的问题:
如果我在运行的记录器中间开始计算,我不知道如何计算运行时间。这意味着我没有看到开始标志但是停止标志。这表明过去必须发生开始标志。

数据:

val ds_notworking = spark.sparkContext.parallelize(Seq(
      ("2017-01-01 02:00:00", "foo", "1"),
      ("2017-01-01 03:00:00", null, "2"),
      ("2017-01-01 04:00:00", "stop", "1"),
      ("2017-01-01 05:00:00", "stop", "2"),
      ("2017-01-01 06:00:00", "start", "1"),
      ("2017-01-01 07:00:00", "start", "2"),
      ("2017-01-01 08:00:00", "foo", "2"),
      ("2017-01-01 09:00:00", "blub", "2"),
      ("2017-01-01 10:00:00", "stop", "3"),
      ("2017-01-01 11:00:00", null, "3"),
      ("2017-01-01 12:00:00", "ASC_c", "4"),
      ("2017-01-01 13:00:00", "stop", "5" ),
      ("2017-01-01 14:00:00", null, "3"),
      ("2017-01-01 15:00:00", "ASC_c", "4"),
    )).toDF("timestamp", "status", "msg")

通缉输出:

+-------------------+------+---+-------+-------+---------+-----+
|          timestamp|status|msg|started|stopped|engWindow|runt |
+-------------------+------+---+-------+-------+---------+-----+
|2017-01-01 02:00:00|   foo|  1|      0|      0|        0| 120 |
|2017-01-01 03:00:00|  null|  2|      0|      0|        0| 120 |
|2017-01-01 04:00:00|  stop|  1|      0|     -1|       -1|  60 |
|2017-01-01 05:00:00|  stop|  2|      0|     -1|       -1|   0 |
|2017-01-01 06:00:00| start|  1|      1|      0|        1|  60 |
|2017-01-01 07:00:00| start|  2|      1|      0|        1| 120 |
|2017-01-01 08:00:00|   foo|  2|      0|      0|        0| 120 |
|2017-01-01 09:00:00|  blub|  2|      0|      0|        0| 120 |
|2017-01-01 10:00:00|  stop|  3|      0|     -1|       -1|  60 |
|2017-01-01 11:00:00|  null|  3|      0|      0|        0|  60 |
|2017-01-01 12:00:00| ASC_c|  4|      0|      0|        0|  60 |
|2017-01-01 13:00:00|  stop|  5|      0|     -1|       -1|   0 |
|2017-01-01 14:00:00|  null|  3|      0|      0|        0|   0 |
|2017-01-01 15:00:00| ASC_c|  4|      0|      0|        0|   0 |
+-------------------+------+---+-------+-------+---------+-----+

当只有一个记录器实例可以同时运行时,我已经解决了这个问题:

 .withColumn("engWindow", last($"engFlag", true).over(systemWindow.rowsBetween(Window.unboundedPreceding, 0)))

但遗憾的是,有两个或更多实例,我不知道如何实现这一目标。 如果有人能指出我正确的方向,那就太好了。

1 个答案:

答案 0 :(得分:0)

我想我找到了答案。我正在考虑这种复杂的方式 虽然我不确定是否存在这种方法不起作用的情况。

我总结了我在工作示例中所做的标志,按时间戳顺序排列数据,找到最小值并将此值添加到当前值。这应始终指示正确运行的记录器数量。

 val ds2 = ds_notworking
      .withColumn("started", when($"status" === "start", 1).otherwise(lit(0)))
      .withColumn("stopped", when($"status" === "stop", -1).otherwise(lit(0)))
      .withColumn("engFlag", when($"started" === 1, $"started").otherwise($"stopped"))
      .withColumn("engWindow", sum($"engFlag").over(Window.orderBy($"timestamp")))
      .withColumn("newEngWindow", $"engWindow" - min($"engWindow").over(Window.orderBy($"timestamp".desc)))
      .withColumn("runtime2", when($"newEngWindow" > 0,
        (unix_timestamp(lead($"timestamp", 1).over(Window.orderBy($"timestamp"))) - unix_timestamp($"timestamp"))/60*$"newEngWindow").otherwise(lit(0)))

编辑:也许这可以更准确地计算最小值并将其应用于整个窗口。

.withColumn("test1", last(min($"engWindow").over(Window.orderBy($"timestamp"))).over(Window.orderBy($"timestamp").rowsBetween(Window.unboundedPreceding, Window.unboundedFollowing)))

输出:

+-------------------+------+---+-------+-------+-------+---------+------------+--------+
|          timestamp|status|msg|started|stopped|engFlag|engWindow|newEngWindow|runtime2|
+-------------------+------+---+-------+-------+-------+---------+------------+--------+
|2017-01-01 02:00:00|   foo|  1|      0|      0|      0|        0|           2|   120.0|
|2017-01-01 03:00:00|  null|  2|      0|      0|      0|        0|           2|   120.0|
|2017-01-01 04:00:00|  stop|  1|      0|     -1|     -1|       -1|           1|    60.0|
|2017-01-01 05:00:00|  stop|  2|      0|     -1|     -1|       -2|           0|     0.0|
|2017-01-01 06:00:00| start|  1|      1|      0|      1|       -1|           1|    60.0|
|2017-01-01 07:00:00| start|  2|      1|      0|      1|        0|           2|   120.0|
|2017-01-01 08:00:00|   foo|  2|      0|      0|      0|        0|           2|   120.0|
|2017-01-01 09:00:00|  blub|  2|      0|      0|      0|        0|           2|   120.0|
|2017-01-01 10:00:00|  stop|  3|      0|     -1|     -1|       -1|           1|    60.0|
|2017-01-01 11:00:00|  null|  3|      0|      0|      0|       -1|           1|    60.0|
|2017-01-01 12:00:00| ASC_c|  4|      0|      0|      0|       -1|           1|    60.0|
|2017-01-01 13:00:00|  stop|  5|      0|     -1|     -1|       -2|           0|     0.0|
|2017-01-01 14:00:00|  null|  3|      0|      0|      0|       -2|           0|     0.0|
|2017-01-01 15:00:00| ASC_c|  4|      0|      0|      0|       -2|           0|     0.0|
+-------------------+------+---+-------+-------+-------+---------+------------+--------+