Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 如何根据以前的连续行筛选出行?_Apache Spark_Apache Spark Sql - Fatal编程技术网

Apache spark 如何根据以前的连续行筛选出行?

Apache spark 如何根据以前的连续行筛选出行?,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我有一个要求,数据帧按col1(时间戳)排序,我需要按col2过滤 任何col2值小于前一行col2值的行,我都需要过滤掉该行。结果应该是col2值单调递增 请注意,这不仅仅是两行 例如,假设4行的col2的值为4,2,3,5。结果应为4,5,因为第二行和第三行都小于4(第一行值) 请注意: 第2行和第3行因其值小于第1行中的值而被过滤掉,即第4行 第5行的值小于第4行的值,即第6行,因此将其过滤掉 一般来说,有没有一种方法可以根据一行的值与前几行中的值的比较来筛选行?我认为您所追求的是运行

我有一个要求,数据帧按col1(时间戳)排序,我需要按col2过滤

任何col2值小于前一行col2值的行,我都需要过滤掉该行。结果应该是col2值单调递增

请注意,这不仅仅是两行

例如,假设4行的col2的值为4,2,3,5。结果应为4,5,因为第二行和第三行都小于4(第一行值)

请注意:

  • 第2行和第3行因其值小于第1行中的值而被过滤掉,即第4行
  • 第5行的值小于第4行的值,即第6行,因此将其过滤掉

一般来说,有没有一种方法可以根据一行的值与前几行中的值的比较来筛选行?

我认为您所追求的是运行最大值()。这总是导致我使用窗口聚合

// I made the input a bit more tricky
val input = Seq(
  (1,4), (2,2), (3,3), (4,5), (5, 1), (6, 9), (7, 6)
).toDF("timestamp", "value")
scala> input.show
+---------+-----+
|timestamp|value|
+---------+-----+
|        1|    4|
|        2|    2|
|        3|    3|
|        4|    5|
|        5|    1|
|        6|    9|
|        7|    6|
+---------+-----+
我的目标是实现以下预期结果。如果我错了,请纠正我

val expected = Seq((1,4), (4,5), (6, 9)).toDF("timestamp", "value")
scala> expected.show
+---------+-----+
|timestamp|value|
+---------+-----+
|        1|    4|
|        4|    5|
|        6|    9|
+---------+-----+
“运行”问题的诀窍是在定义窗口规范时使用
rangeBetween

import org.apache.spark.sql.expressions.Window
val ts = Window
  .orderBy("timestamp")
  .rangeBetween(Window.unboundedPreceding, Window.currentRow)
使用WindowSpec,您可以从结果中过滤出想要去除的内容,然后就完成了

val result = input
  .withColumn("running_max", max("value") over ts)
  .where($"running_max" === $"value")
  .select("timestamp", "value")

scala> result.show
18/05/29 22:09:18 WARN WindowExec: No Partition Defined for Window operation! Moving all data to a single partition, this can cause serious performance degradation.
+---------+-----+
|timestamp|value|
+---------+-----+
|        1|    4|
|        4|    5|
|        6|    9|
+---------+-----+

正如您所看到的,它的效率不是很高,因为它只使用一个分区(这会导致单线程执行不佳,因此与在一台机器上运行实验没有太大区别)


我认为我们可以对输入进行分区,计算部分运行的最大值,然后合并部分结果,再次运行运行的最大值计算。只是一个我自己还没有尝试过的想法。

检查与运行最大值的相等性应该可以做到:

val input = Seq((1,4), (2,2), (3,3), (4,5), (5, 1), (6, 9), (7, 6)).toDF("timestamp", "value")

input.show()

+---------+-----+
|timestamp|value|
+---------+-----+
|        1|    4|
|        2|    2|
|        3|    3|
|        4|    5|
|        5|    1|
|        6|    9|
|        7|    6|
+---------+-----+


input
  .withColumn("max",max($"value").over(Window.orderBy($"timestamp")))
  .where($"value"===$"max").drop($"max")
  .show()

+---------+-----+
|timestamp|value|
+---------+-----+
|        1|    4|
|        4|    5|
|        6|    9|
+---------+-----+

rangeBetween
是不需要的,如果窗口指定了顺序,它会自动使用“running”Maximum。我想我可能已经看到了Spark版本中需要它的地方,因此我将它作为安全网包括在内。它不会造成伤害,并且让事情变得更容易预测。好吧,但是我建议使用
rowsBetween
使它更易于阅读。谢谢Jacek提供了详细的答案。还感谢您回答我关于分区警告的后续问题。运行max是关键。@JacekLaskowski它们基本上是不同的,
rowsBetween
是在“行数”中设置一个帧,
rangeBetween
使用其他度量来定义一个帧,例如,无论数据是如何采样的,用于计算10米以上的滑动平均值(在这种情况下,行数是动态计算的).
val input = Seq((1,4), (2,2), (3,3), (4,5), (5, 1), (6, 9), (7, 6)).toDF("timestamp", "value")

input.show()

+---------+-----+
|timestamp|value|
+---------+-----+
|        1|    4|
|        2|    2|
|        3|    3|
|        4|    5|
|        5|    1|
|        6|    9|
|        7|    6|
+---------+-----+


input
  .withColumn("max",max($"value").over(Window.orderBy($"timestamp")))
  .where($"value"===$"max").drop($"max")
  .show()

+---------+-----+
|timestamp|value|
+---------+-----+
|        1|    4|
|        4|    5|
|        6|    9|
+---------+-----+