ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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


z
zero323

对于 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)(注意 head(n: Int) 方法中的 limit(n).queryExecution),所以以下都是等价的,至少据我所知,您不必捕获 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 的执行计划正在执行一些复杂的操作,从而阻止 spark 走捷径。例如,如果您只是从 parquet 文件中读取 df = spark.read.parquet(...),我很确定 spark 只会读取一个文件分区。但是,如果您的 df 正在执行其他操作,例如聚合,您可能会无意中强制 spark 读取和处理大部分(如果不是全部)源数据。
只是向 AVOID 报告我的经验:我天真地使用 df.limit(1).count()。在大型数据集上,它比@hulin003 报告的示例花费更多的时间,这些示例几乎是瞬时的
z
zero323

我会说只是抓住底层的RDD。在斯卡拉:

df.rdd.isEmpty

在 Python 中:

df.rdd.isEmpty()

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


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

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

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

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

大约需要 9366 毫秒 大约需要 5607 毫秒 大约需要 1921 毫秒

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


出于好奇......这是用什么大小的DataFrames测试的?
我已经测试了 1000 万行......并且得到了与 df.count() 或 df.rdd.isEmpty() 相同的时间
B
Beryllium

从 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()。所以这不应该明显变慢。如果数据集包含很多列(可能是非规范化的嵌套数据),它可能会更快。无论如何,您必须少输入:-)
当心:我正在使用 .option("mode", "DROPMALFORMED") 并且 df.isEmpty 返回 falsedf.head(1).isEmpty 返回了 true 的正确结果,因为...所有行格式错误(上游有人更改了我的架构)。
A
Aakil Fernandes

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


如果数据框为空,则抛出“java.util.NoSuchElementException: next on empty iterator”; [火花1.3.1]
R
Ram Ghadiyaram

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

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

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

https://i.stack.imgur.com/tBnaN.png


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

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

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

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


S
Shaido

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

A
Adelholzener

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

len(df.head(1)) > 0

B
Bose

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

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


Z
ZygD

PySpark 3.3.0+ / Scala 2.4.0+

df.isEmpty()

“DataFrame”对象没有属性“isEmpty”。火花3.0
在 PySpark 中,它仅从 3.3.0 版本开始引入
S
Shekhar Koirala

我发现在某些情况下:

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

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

这与“长度”相同或将 take() 替换为 head()

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

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

A
Arya McCarthy
df1.take(1).length>0

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


J
Joy Jedidja Ndjama

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

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

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

df.count() > 0

或者

bool(df.head(1))

S
Stephen Rauch

你可以这样做:

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

是否需要两个数据帧(sqlContext.emptyDataFramedf)的 schema 相同才能返回 true
这行不通。 eq 继承自 AnyRef测试参数 (that) 是否是对接收器对象 (this) 的引用。
J
Jordan Morris

dataframe.limit(1).count > 0

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

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


所有这些都是糟糕的选择,花费几乎相同的时间
@PushpendraJaiswal 是的,在一个糟糕的选择世界中,我们应该选择最好的错误选择