如何检查火花数据框是不是为空?

Posted

技术标签:

【中文标题】如何检查火花数据框是不是为空?【英文标题】:How to check if spark dataframe is empty?如何检查火花数据框是否为空? 【发布时间】:2015-09-22 02:52:55 【问题描述】:

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

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

【问题讨论】:

【参考方案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 个主要解决方案:

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

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

    大约需要 9366 毫秒 大约需要 5607 毫秒 大约需要 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】:

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

df.isEmpty()

【讨论】:

【参考方案12】:

我发现在某些情况下:

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

【讨论】:

【参考方案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 是的,在一个糟糕选择的世界里,我们应该选择最好的错误选择

以上是关于如何检查火花数据框是不是为空?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用火花流检查 rdd 是不是为空?

检查数据框中的记录数是不是大于零而不使用计数火花

如何设置一个空结构,所有字段为空,在火花中为空

检查列表和数据框是不是为空

spark中的isNullOrEmpty函数检查数据框中的列是不是为空或空字符串

如何在javascript中检查我的任何文本框是不是为空[重复]