Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.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
基于spark dataframe scala中的列值筛选行_Scala_Apache Spark_Dataframe_Apache Spark Sql - Fatal编程技术网

基于spark dataframe scala中的列值筛选行

基于spark dataframe scala中的列值筛选行,scala,apache-spark,dataframe,apache-spark-sql,Scala,Apache Spark,Dataframe,Apache Spark Sql,我有一个dataframespark: id value 3 0 3 1 3 0 4 1 4 0 4 0 我想创建一个新的数据帧: 3 0 3 1 4 1 需要删除每个id的1value之后的所有行。我尝试了spark dateframeScala中的窗口函数。但无法找到解决方案。似乎我走错了方向 我正在寻找Scala的解决方案。谢谢 使用单调递增id的输出 scala> val data = Seq((3,0),(3,1),(3,

我有一个dataframespark:

id  value 
3     0
3     1
3     0
4     1
4     0
4     0
我想创建一个新的数据帧:

3 0
3 1
4 1
需要删除每个id的1value之后的所有行。我尝试了spark dateframeScala中的窗口函数。但无法找到解决方案。似乎我走错了方向

我正在寻找Scala的解决方案。谢谢

使用单调递增id的输出

 scala> val data = Seq((3,0),(3,1),(3,0),(4,1),(4,0),(4,0)).toDF("id", "value")
data: org.apache.spark.sql.DataFrame = [id: int, value: int]

scala> val minIdx = dataWithIndex.filter($"value" === 1).groupBy($"id").agg(min($"idx")).toDF("r_id", "min_idx")
minIdx: org.apache.spark.sql.DataFrame = [r_id: int, min_idx: bigint]

scala> dataWithIndex.join(minIdx,($"r_id" === $"id") && ($"idx" <= $"min_idx")).select($"id", $"value").show
+---+-----+
| id|value|
+---+-----+
|  3|    0|
|  3|    1|
|  4|    1|
+---+-----+
如果我们在原始数据帧中进行排序转换,那么解决方案将不起作用。这一次,单调递增的id是基于原始DF而不是排序的DF生成的。我以前错过了这个需求

欢迎所有建议

一种方法是使用单调递增的id和自联接:

val data = Seq((3,0),(3,1),(3,0),(4,1),(4,0),(4,0)).toDF("id", "value")
data.show
+---+-----+
| id|value|
+---+-----+
|  3|    0|
|  3|    1|
|  3|    0|
|  4|    1|
|  4|    0|
|  4|    0|
+---+-----+
现在,我们生成一个名为idx的列,其长度不断增加:

现在我们得到每个id的minidx,其中value=1:

现在,我们将minidx连接回原始数据帧:


嗨,我找到了使用窗口和自连接的解决方案

val data = Seq((3,0,2),(3,1,3),(3,0,1),(4,1,6),(4,0,5),(4,0,4),(1,0,7),(1,1,8),(1,0,9),(2,1,10),(2,0,11),(2,0,12)).toDF("id", "value","sorted")

data.show

scala> data.show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
|  3|    0|     2|
|  3|    1|     3|
|  3|    0|     1|
|  4|    1|     6|
|  4|    0|     5|
|  4|    0|     4|
|  1|    0|     7|
|  1|    1|     8|
|  1|    0|     9|
|  2|    1|    10|
|  2|    0|    11|
|  2|    0|    12|
+---+-----+------+




val sort_df=data.sort($"sorted")

scala> sort_df.show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
|  3|    0|     1|
|  3|    0|     2|
|  3|    1|     3|
|  4|    0|     4|
|  4|    0|     5|
|  4|    1|     6|
|  1|    0|     7|
|  1|    1|     8|
|  1|    0|     9|
|  2|    1|    10|
|  2|    0|    11|
|  2|    0|    12|
+---+-----+------+



var window=Window.partitionBy("id").orderBy("$sorted")

 val sort_idx=sort_df.select($"*",rowNumber.over(window).as("count_index"))

val minIdx=sort_idx.filter($"value"===1).groupBy("id").agg(min("count_index")).toDF("idx","min_idx")

val result_id=sort_idx.join(minIdx,($"id"===$"idx") &&($"count_index" <= $"min_idx"))

result_id.show

+---+-----+------+-----------+---+-------+
| id|value|sorted|count_index|idx|min_idx|
+---+-----+------+-----------+---+-------+
|  1|    0|     7|          1|  1|      2|
|  1|    1|     8|          2|  1|      2|
|  2|    1|    10|          1|  2|      1|
|  3|    0|     1|          1|  3|      3|
|  3|    0|     2|          2|  3|      3|
|  3|    1|     3|          3|  3|      3|
|  4|    0|     4|          1|  4|      3|
|  4|    0|     5|          2|  4|      3|
|  4|    1|     6|          3|  4|      3|
+---+-----+------+-----------+---+-------+
仍在寻找更优化的解决方案。谢谢你可以像这样简单地使用groupBy

val df2 = df1.groupBy("id","value").count().select("id","value")
id  value 
3     0
3     1
4     1
4     0
这是您的df1

结果数据帧是df2,这是您预期的输出,如下所示

val df2 = df1.groupBy("id","value").count().select("id","value")
id  value 
3     0
3     1
4     1
4     0

“到目前为止你尝试了什么?”eliasah我尝试了一些基于答案的实验。但到目前为止,你的DF还没有成功吗?@TheArchetypalPaul是的,它是成功的。这是因为你每次都在给show打电话。在我下面的代码中,计算是惰性的-只有在调用我的最终显示后,才会计算原始的val dataWithIndex。但你每次都会打电话给show,强迫重新评估。停止调用show,或者在创建dataWithIndexYeah后立即调用cache,不要深入查看通过单调增加id生成的列-每次查看时可能会得到不同的值-您看到的数字基于分区方案。只需运行代码,不要查看中间值。如果出于理智考虑,希望每次都看到相同的值,请添加dataWithIndex.cache行。但它不会改变整体结果——它只是让你可以在显微镜下观察每一步,而不会觉得自己疯了。谢谢@davidGirffin。我没有正确获得输出,我检查了中间结果。我已经更新了问题本身的输出。请你看一看。回答。这是因为每次你打电话给show,它都会迫使你重新评估。这就像量子力学——你通过观察来改变它的值。如果你像我一样运行代码-只有最后一场-它会得到正确的结果。
val df2 = df1.groupBy("id","value").count().select("id","value")
id  value 
3     0
3     1
3     0
4     1
4     0
4     0
id  value 
3     0
3     1
4     1
4     0
use isin method and filter as below:

val data = Seq((3,0,2),(3,1,3),(3,0,1),(4,1,6),(4,0,5),(4,0,4),(1,0,7),(1,1,8),(1,0,9),(2,1,10),(2,0,11),(2,0,12)).toDF("id", "value","sorted")
val idFilter = List(1, 2)
 data.filter($"id".isin(idFilter:_*)).show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
|  1|    0|     7|
|  1|    1|     8|
|  1|    0|     9|
|  2|    1|    10|
|  2|    0|    11|
|  2|    0|    12|
+---+-----+------+

Ex: filter based on val
val valFilter = List(0)
data.filter($"value".isin(valFilter:_*)).show
+---+-----+------+
| id|value|sorted|
+---+-----+------+
|  3|    0|     2|
|  3|    0|     1|
|  4|    0|     5|
|  4|    0|     4|
|  1|    0|     7|
|  1|    0|     9|
|  2|    0|    11|
|  2|    0|    12|
+---+-----+------+