【问题标题】:Scala filter out rows where any column2 matches column1Scala过滤掉任何column2与column1匹配的行
【发布时间】:2020-09-22 20:58:41
【问题描述】:

你好 Stackoverflow,

我想删除数据框中的所有行,其中 A 列与 B 列中的任何不同值匹配。我希望这个代码块完全做到这一点,但它似乎也删除了 B 列为空的值,这很奇怪,因为过滤器无论如何都应该只考虑 A 列。如何修复此代码以执行预期的行为,即删除数据框中的所有行,其中 A 列与 B 列中的任何不同值匹配。




import spark.implicits._

val df = Seq(

      (scala.math.BigDecimal(1) , null),

      (scala.math.BigDecimal(2), scala.math.BigDecimal(1)),

      (scala.math.BigDecimal(3), scala.math.BigDecimal(4)),

      (scala.math.BigDecimal(4), null),

      (scala.math.BigDecimal(5), null),

      (scala.math.BigDecimal(6), null)

    ).toDF("A", "B")



// correct, has 1, 4

val to_remove = df

    .filter(

    df.col("B").isNotNull

    ).select(

    df("B")

).distinct()





// incorrect, returns 2, 3 instead of 2, 3, 5, 6

val final = df.filter(!df.col("A").isin(to_remove.col("B")))



// 4 != 2

assert(4 === final.collect().length)

【问题讨论】:

    标签: scala dataframe apache-spark filter apache-spark-sql


    【解决方案1】:

    isin 函数接受一个列表。但是,在您的代码中,您传递的是 Dataset[Row]。根据文档https://spark.apache.org/docs/1.6.0/api/scala/index.html#org.apache.spark.sql.Column@isin%28scala.collection.Seq%29 它被声明为

    def isin(list: Any*): Column

    您首先需要将值提取到序列中,然后在isin 函数中使用它。请注意,这可能会对性能产生影响。

    scala> val to_remove = df.filter(df.col("B").isNotNull).select(df("B")).distinct().collect.map(_.getDecimal(0))
    to_remove: Array[java.math.BigDecimal] = Array(1.000000000000000000, 4.000000000000000000)
    
    scala> val finaldf = df.filter(!df.col("A").isin(to_remove:_*))
    finaldf: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [A: decimal(38,18), B: decimal(38,18)]
    
    scala> finaldf.show
    +--------------------+--------------------+
    |                   A|                   B|
    +--------------------+--------------------+
    |2.000000000000000000|1.000000000000000000|
    |3.000000000000000000|4.000000000000000000|
    |5.000000000000000000|                null|
    |6.000000000000000000|                null|
    +--------------------+--------------------+
    

    【讨论】:

      【解决方案2】:

      将过滤条件!df.col("A").isin(to_remove.col("B"))更改为!df.col("A").isin(to_remove.collect.map(_.getDecimal(0)):_*)

      检查下面的代码。

      val finaldf = df
      .filter(!df
               .col("A")
               .isin(to_remove.map(_.getDecimal(0)).collect:_*)
             )
      
      scala> finaldf.show
      +--------------------+--------------------+
      |                   A|                   B|
      +--------------------+--------------------+
      |2.000000000000000000|1.000000000000000000|
      |3.000000000000000000|4.000000000000000000|
      |5.000000000000000000|                null|
      |6.000000000000000000|                null|
      +--------------------+--------------------+
      
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-15
        • 2020-06-11
        • 2022-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-12
        相关资源
        最近更新 更多