【问题标题】:How to check if spark dataframe is empty?如何检查火花数据框是否为空?
【发布时间】:2015-12-18 21:14:30
【问题描述】:

现在,我必须使用df.count > 0 来检查DataFrame 是否为空。但这有点低效。有没有更好的方法来做到这一点?

PS:我想检查它是否为空,所以我只保存DataFrame,如果它不为空

【问题讨论】:

    标签: apache-spark pyspark apache-spark-sql


    【解决方案1】:

    对于 Spark 2.1.0,我的建议是使用 head(n: Int)take(n: Int)isEmpty,以您最清楚的意图为准。

    df.head(1).isEmpty
    df.take(1).isEmpty
    

    与 Python 等效:

    len(df.head(1)) == 0  # or bool(df.head(1))
    len(df.take(1)) == 0  # or bool(df.take(1))
    

    如果 DataFrame 为空,则使用 df.first()df.head() 都将返回 java.util.NoSuchElementExceptionfirst() 直接调用head(),后者调用head(1).head

    def first(): T = head()
    def head(): T = head(1).head
    

    head(1) 返回一个数组,因此在该数组上使用head 会在 DataFrame 为空时导致java.util.NoSuchElementException

    def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan)
    

    所以不要调用head(),而是直接使用head(1)获取数组,然后就可以使用isEmpty了。

    take(n) 也等价于head(n)...

    def take(n: Int): Array[T] = head(n)
    

    并且limit(1).collect() 等价于head(1)(注意limit(n).queryExecutionhead(n: Int) 方法中),所以以下都是等价的,至少据我所知,你不必抓住java.util.NoSuchElementException DataFrame 为空时的异常。

    df.head(1).isEmpty
    df.take(1).isEmpty
    df.limit(1).collect().isEmpty
    

    我知道这是一个较老的问题,因此希望它对使用新版本 Spark 的人有所帮助。

    【讨论】:

    • 对于那些使用 pyspark 的人。 isEmpty 不是一个东西。改用 len(d.head(1)) > 0。
    • 为什么比df.rdd.isEmpty更好?
    • df.head(1).isEmpty 需要大量时间是否有任何其他优化解决方案。
    • 嘿@Rakesh Sabbani,如果df.head(1) 花费大量时间,那可能因为您的df 的执行计划正在执行一些复杂的事情,从而阻止了火花从走捷径。例如,如果你只是从 parquet 文件中读取,df = spark.read.parquet(...),我很确定 spark 只会读取一个文件分区。但是,如果您的 df 正在执行其他操作,例如聚合,您可能会无意中强制 spark 读取和处理大部分(如果不是全部)源数据。
    • 只是向 AVOID 报告我的经历:我天真地使用了 df.limit(1).count()。在大型数据集上,它比@hulin003 报告的示例花费更多的时间,这些示例几乎是瞬时的
    【解决方案2】:

    我会说只是抓住底层RDD。在 Scala 中:

    df.rdd.isEmpty
    

    在 Python 中:

    df.rdd.isEmpty()
    

    话虽如此,这只是调用take(1).length,所以它会做与Rohan回答相同的事情......只是可能稍微更明确一点?

    【讨论】:

    • 在我的情况下,这比 df.count() == 0 慢得惊人
    • 转换为 rdd 不是一项繁重的任务吗?
    • 并非如此。在大多数情况下,RDD 仍然是 Spark 的基础。
    • 不要将 df 转换为 RDD。它减慢了这个过程。如果你转换它会将整个 DF 转换为 RDD 并检查它是否为空。想想如果 DF 有数百万行,那么转换为 RDD 本身就需要很多时间。
    • .rdd 大大减慢了整个过程
    【解决方案3】:

    我有同样的问题,我测试了 3 个主要解决方案:

    1. (df != null) && (df.count > 0)
    2. df.head(1).isEmpty() @hulin003 建议
    3. df.rdd.isEmpty() @Justin Pihony 建议

    当然,这 3 种方法都有效,但是就性能而言,这是我发现的,当在我的机器上的同一个 DF 上执行这些方法时,就执行时间而言:

    1. 大约需要 9366 毫秒
    2. 大约需要 5607 毫秒
    3. 大约需要 1921 毫秒

    因此我认为最好的解决方案是 df.rdd.isEmpty() @Justin Pihony 建议

    【讨论】:

    • 出于好奇......这是用什么大小的 DataFrames 测试的?
    【解决方案4】:

    从 Spark 2.4.0 开始有Dataset.isEmpty

    implementation 是:

    def isEmpty: Boolean = 
      withAction("isEmpty", limit(1).groupBy().count().queryExecution) { plan =>
        plan.executeCollect().head.getLong(0) == 0
    }
    

    请注意,DataFrame 在 Scala 中不再是一个类,它只是一个 type alias(可能已随 Spark 2.0 更改):

    type DataFrame = Dataset[Row]
    

    【讨论】:

    • isEmpty 比 df.head(1).isEmpty 慢
    • @Sandeep540 真的吗?基准?您的提案至少实例化了一行。 Spark 实现只是传输一个数字。 head() 也在使用 limit(),groupBy() 并没有真正做任何事情,它需要获取一个 RelationalGroupedDataset,它反过来提供 count()。所以这不应该明显变慢。如果数据集包含很多列(可能是非规范化的嵌套数据),它可能会更快。无论如何,您必须少输入:-)
    【解决方案5】:

    您可以利用head()(或first())函数来查看DataFrame 是否只有一行。如果是,则不为空。

    【讨论】:

    • 如果数据框为空,则抛出“java.util.NoSuchElementException: next on empty iterator”; [火花 1.3.1]
    【解决方案6】:

    如果您选择df.count > 0。它计算所有执行程序中所有分区的计数,并将它们添加到 Driver。当您处理数百万行时,这需要一段时间。

    最好的方法是执行df.take(1) 并检查它是否为空。这将返回java.util.NoSuchElementException,所以最好尝试一下df.take(1)

    take(1) 完成而不是空行时,数据框返回错误。我已经突出显示了引发错误的特定代码行。

    【讨论】:

    • 如果您在包含数百万条记录的海量数据帧上运行此程序,count 方法将需要一些时间。
    • 当 df 为空时使用 df.take(1) 会导致返回一个无法与 null 比较的空 ROW
    • 我在 try/catch 块中使用 first() 而不是 take(1),它可以工作
    • @LetsPlayYahtzee 我已经用相同的运行和显示错误的图片更新了答案。 take(1) 返回 Array[Row]。当 Array 没有任何值时,默认情况下它会给出 ArrayOutOfBounds。所以我不认为它给出了一个空行。我会说观察这一点并改变投票。
    【解决方案7】:

    对于 Java 用户,您可以在数据集上使用它:

    public boolean isDatasetEmpty(Dataset<Row> ds) {
            boolean isEmpty;
            try {
                isEmpty = ((Row[]) ds.head(1)).length == 0;
            } catch (Exception e) {
                return true;
            }
            return isEmpty;
    }
    

    这会检查所有可能的情况(空、空)。

    【讨论】:

      【解决方案8】:

      在 Scala 中,您可以使用隐式添加方法 isEmpty()nonEmpty() 到 DataFrame API,这将使代码更易于阅读。

      object DataFrameExtensions {
        implicit def extendedDataFrame(dataFrame: DataFrame): ExtendedDataFrame = 
          new ExtendedDataFrame(dataFrame: DataFrame)
      
        class ExtendedDataFrame(dataFrame: DataFrame) {
          def isEmpty(): Boolean = dataFrame.head(1).isEmpty // Any implementation can be used
          def nonEmpty(): Boolean = !isEmpty
        }
      }
      

      在这里,也可以添加其他方法。要使用隐式转换,请在要使用扩展功能的文件中使用import DataFrameExtensions._。之后,这些方法可以直接使用:

      val df: DataFrame = ...
      if (df.isEmpty) {
        // Do something
      }
      

      【讨论】:

        【解决方案9】:

        在 PySpark 上,您还可以使用此 bool(df.head(1)) 来获取 TrueFalse

        如果数据框不包含任何行,则返回 False

        【讨论】:

          【解决方案10】:

          如果你使用 Pyspark,你也可以这样做:

          len(df.head(1)) > 0
          

          【讨论】:

            【解决方案11】:

            我发现在某些情况下:

            >>>print(type(df))
            <class 'pyspark.sql.dataframe.DataFrame'>
            
            >>>df.take(1).isEmpty
            'list' object has no attribute 'isEmpty'
            

            "length" 也一样,或者用 head() 替换 take()

            [解决方案]我们可以使用的问题。

            >>>df.limit(2).count() > 1
            False
            

            【讨论】:

              【解决方案12】:

              在 Spark 2.4 版中引入了 DataFrames 的 isEmpty() 方法。因此,在任何版本的 spark 2.4 或更高版本上检查 DataFrame 是否为空的最佳方法是使用函数 isEmpty()

              df.isEmpty()
              

              【讨论】:

                【解决方案13】:
                df1.take(1).length>0
                

                take 方法返回行数组,因此如果数组大小为零,则df 中没有记录。

                【讨论】:

                  【解决方案14】:

                  假设我们有以下空数据框:

                  df = spark.sql("show tables").limit(0)
                  

                  如果您使用的是 Spark 2.1,对于 pyspark,要检查此数据框是否为空,您可以使用:

                  df.count() > 0
                  

                  或者

                  bool(df.head(1))
                  

                  【讨论】:

                    【解决方案15】:

                    你可以这样做:

                    val df = sqlContext.emptyDataFrame
                    if( df.eq(sqlContext.emptyDataFrame) )
                        println("empty df ")
                    else 
                        println("normal df")
                    

                    【讨论】:

                    • 是否需要两个数据帧(sqlContext.emptyDataFramedf)的schema 相同才能返回true
                    • 这行不通。 eq 继承自 AnyRef测试参数 (that) 是否是对接收器对象 (this) 的引用。
                    【解决方案16】:

                    dataframe.limit(1).count &gt; 0

                    这也会触发作业,但由于我们选择的是单个记录,因此即使在十亿规模记录的情况下,时间消耗也可能要低得多。

                    来自: https://medium.com/checking-emptiness-in-distributed-objects/count-vs-isempty-surprised-to-see-the-impact-fa70c0246ee0

                    【讨论】:

                    • 所有这些都是糟糕的选择,花费几乎相同的时间
                    • @PushpendraJaiswal 是的,在一个糟糕选择的世界里,我们应该选择最好的错误选择
                    猜你喜欢
                    • 2016-12-26
                    • 1970-01-01
                    • 2020-04-20
                    • 1970-01-01
                    • 1970-01-01
                    • 2022-01-24
                    相关资源
                    最近更新 更多