如何检查Spark数据框是否为空?

How to check if spark dataframe is empty?

现在,我必须使用df.count > 0来检查DataFrame是否为空。 但这效率很低。 有什么更好的方法吗?

谢谢。

PS:我想检查它是否为空,以便仅在DataFrame不为空时保存它


对于Spark 2.1.0,我的建议是将head(n: Int)take(n: Int)isEmpty一起使用,无论哪一个对您有最明确的意图。

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

与Python等效:

1
2
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

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

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

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

因此,与其直接调用head(),不如直接使用head(1)来获取数组,然后可以使用isEmpty

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

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

并且limit(1).collect()等效于head(1)(在head(n: Int)方法中注意limit(n).queryExecution),因此以下内容都是等效的,至少从我的判断出发,并且您不必抓住java.util.NoSuchElementException DataFrame为空时发生异常。

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

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


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

1
df.rdd.isEmpty

在Python中:

1
df.rdd.isEmpty()

话虽这么说,所有这一切都称为take(1).length,所以它会做与Rohan回答的相同的事情……也许稍微更明确些?


您可以利用head()(或first())功能查看DataFrame是否具有单行。如果是这样,则它不是空的。


从Spark 2.4.0开始,存在Dataset.isEmpty

它的实现是:

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

请注意,DataFrame不再是Scala中的类,而只是类型别名(可能在Spark 2.0中更改了):

1
type DataFrame = Dataset[Row]


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

1
2
3
4
5
6
7
8
9
public boolean isDatasetEmpty(Dataset<Row> ds) {
        boolean isEmpty;
        try {
            isEmpty = ((Row[]) ds.head(1)).length == 0;
        } catch (Exception e) {
            return true;
        }
        return isEmpty;
}

这将检查所有可能的情况(空,null)。


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

最好的方法是执行df.take(1)并检查其是否为null。这将返回java.util.NoSuchElementException,因此最好尝试尝试df.take(1)

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

enter image description here


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

1
2
3
4
5
6
7
8
9
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._。之后,可以按如下方式直接使用这些方法:

1
2
3
4
val df: DataFrame = ...
if (df.isEmpty) {
  // Do something
}

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

  • df!= null df.count> 0
  • df.head(1).isEmpty()如@ hulin003建议
  • df.rdd.isEmpty @Justin Pihony建议
  • 当然这3种有效,但是就性能而言,这是我在执行时间方面在我的机器的同一DF上执行这些方法时发现的:

  • 大约需要9366ms
  • 大约需要5607毫秒
  • 大约需要1921ms
  • 因此,我认为最好的解决方案是@Justin Pihony建议的df.rdd.isEmpty


    在PySpark上,您也可以使用此bool(df.head(1))获得False值的True

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


    如果您使用的是Pypsark,则还可以执行以下操作:

    1
    len(df.head(1)) > 0

    我发现在某些情况下:

    1
    2
    3
    4
    5
    >>>print(type(df))
    <class 'pyspark.sql.dataframe.DataFrame'>

    >>>df.take(1).isEmpty
    'list' object has no attribute 'isEmpty'

    这与"长度"相同,或由head()替换take()

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

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

    dataframe.limit(1).count > 0

    这也触发了一项工作,但是由于我们选择的是单条记录,即使是十亿规模的记录,时间消耗也可能要低得多。

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


    1
    df1.take(1).length>0

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


    您可以这样做:

    1
    2
    3
    4
    5
    val df = sqlContext.emptyDataFrame
    if( df.eq(sqlContext.emptyDataFrame) )
        println("empty df")
    else
        println("normal df")