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


100

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

谢谢。

PS:我想检查一下是否为空,以便只保存DataFrame不为空的

Answers:


153

对于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.NoSuchElementException。直接first()呼叫head(),即呼叫head(1).head

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

head(1)返回一个数组,因此采用head该数组会导致java.util.NoSuchElementExceptionDataFrame为空。

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异常,当数据框为空。

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

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


19
对于那些使用pyspark的人。isEmpty不是一回事。改为len(d.head(1))> 0。
AntiPawn79 '17

3
为什么这更好df.rdd.isEmpty呢?
Dan Ciborowski-MSFT

1
df.head(1).isEmpty需要花费大量时间,是否还有其他优化的解决方案。
Rakesh Sabbani

1
嘿@Rakesh Sabbani,如果df.head(1)要花费大量时间,可能是因为您df的执行计划做的事情很复杂,导致spark无法采用快捷方式。例如,如果您只是从实木复合地板文件中读取df = spark.read.parquet(...),我敢肯定,spark只会读取一个文件分区。但是,如果您df正在执行聚合之类的其他操作,则可能会无意间迫使Spark读取和处理大部分(如果不是全部)源数据。
hulin003

只是向AVOID报告我的经验:我很df.limit(1).count()天真。在大型数据集上,它花费的时间比@ hulin003所报告的示例几乎是即时的要
多得多

45

我会说只是抓住基础RDD。在Scala中:

df.rdd.isEmpty

在Python中:

df.rdd.isEmpty()

话虽这么说,所有这一切都是call take(1).length,所以它会做与Rohan回答的一样的事情……也许更明确一点?


6
在我的情况下,这比df.count()== 0慢得多
Architectonic

2
转换为rdd并不繁重吗?
阿洛克

1
并不是的。在大多数情况下,RDD仍是Spark一切的基础。
贾斯汀·皮洪尼

28
不要将df转换为RDD。这会减慢该过程。如果进行转换,它将整个DF转换为RDD,并检查其是否为空。想想如果DF有数百万行,转换到RDD本身会花费很多时间。
Nandakishore

3
.rdd大大减慢了该过程的速度
Raul H

14

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


10
如果dataframe为空,则抛出“ java.util.NoSuchElementException:下一个空迭代器”;[Spark 1.3.1]
FelixHo

6

从Spark 2.4.0开始Dataset.isEmpty

它的实现是:

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

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

type DataFrame = Dataset[Row]

1
的isEmpty比df.head慢(1).isEmpty
Sandeep540

@ Sandeep540真的吗?基准?您的建议至少实例化一行。Spark实现只是传输一个数字。head()也在使用limit(),groupBy()并没有真正做任何事情,需要获得一个RelationalGroupedDataset,后者再提供count()。因此,这应该不会明显变慢。如果数据集包含许多列(可能是非规范化的嵌套数据),则速度可能会更快。顺便说一句,您不必键入太多:-)

5

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

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

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


5

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

最好的方法是执行df.take(1)并检查其是否为空。这样可以java.util.NoSuchElementException更好地进行尝试df.take(1)

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

在此处输入图片说明


1
如果您在具有数百万条记录的海量数据帧上运行此count方法,则该方法将需要一些时间。
TheM00s3 '16

2
我说的也一样,我不确定你为什么不赞成。
Nandakishore

没错,您确实说了同样的话,很遗憾,我没有对您投反对票。
TheM00s3 '16

哦,好吧。对于TheMoos3,我们感到很抱歉,但是无论这样做的人,请注意答案并理解其概念。
Nandakishore

当df为空时使用df.take(1)会导致返回一个空ROW,该行无法与null进行比较
LetsPlayYahtzee

3

在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
}

2

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

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

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

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

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


1
选项3花费的时间更少,为什么要选择第二个?
thinkman

糟糕,您的权利,我使用的是3号,我更新了响应
aName

出于好奇...测试了什么尺寸的DataFrame?
aiguofer

1

我发现在某些情况下:

>>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>

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

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

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

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


1

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

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


0
df1.take(1).length>0

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


-1

dataframe.limit(1).count > 0

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

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


所有这些都是花费几乎相同时间的错误选择
Pushpendra Jaiswal

@PushpendraJaiswal是的,在一个糟糕的选择的世界里,我们应该选择最好的糟糕的选择
Jordan Morris

-2

您可以这样做:

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

1
是否需要schema两个数据帧(sqlContext.emptyDataFramedf)相同才能返回true
y2k-shubham

1
这行不通。eq从继承AnyRef测试参数(that)是否是对接收者对象(this)的引用。
Alper t。Turker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.