检查Spark Dataframe行是否有满足条件的ANY列,并在找到第一个此类列时停止

时间:2019-02-24 23:39:18

标签: apache-spark

以下代码可用于过滤包含值为1的行。图像中有很多列。

import org.apache.spark.sql.types.StructType

val df = sc.parallelize(Seq(
   ("r1", 1, 1),
   ("r2", 6, 4),
   ("r3", 4, 1),
   ("r4", 1, 2)
   )).toDF("ID", "a", "b")

val ones = df.schema.map(c => c.name).drop(1).map(x => when(col(x) === 1, 1).otherwise(0)).reduce(_ + _)

df.withColumn("ones", ones).where($"ones" === 0).show

这里的缺点是,理想情况下,当满足第一个此类条件时,它应该停止。即找到的第一列。好,我们都知道。

但是,如果不使用UDF或非常特定的逻辑,我将找不到一种完美的方法来实现这一目标。地图将处理所有列。

因此可以使用可以在首次发现可能出现时终止的fold(Left)吗?还是其他方法?可能是疏忽。

1 个答案:

答案 0 :(得分:1)

我的第一个想法是使用逻辑表达式并希望发生短路,但似乎火花没有这样做:

df
  .withColumn("ones", df.columns.tail.map(x => when(col(x) === 1, true).otherwise(false)).reduceLeft(_ or _))
  .where(!$"ones")
  .show()

但是我不确定火花是否支持短路,我认为不支持(https://issues.apache.org/jira/browse/SPARK-18712

因此,您也可以在scala的exist上使用懒惰的Seq在行上应用自定义函数:

df
  .map{r => (r.getString(0),r.toSeq.tail.exists(c => c.asInstanceOf[Int]==1))}
  .toDF("ID","ones")
  .show()

此方法类似于UDF,因此不确定是否可以接受。