如何检查火花数据框是不是为空?
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.NoSuchElementException
。 first()
直接调用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).queryExecution
在head(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))
来获取 True
的 False
值
如果数据框不包含任何行,则返回 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.emptyDataFrame
和df
)的schema
相同才能返回true
?
这行不通。 eq
继承自 AnyRef
并测试参数 (that) 是否是对接收器对象 (this) 的引用。【参考方案16】:
dataframe.limit(1).count > 0
这也会触发作业,但由于我们选择的是单个记录,因此即使在十亿规模记录的情况下,时间消耗也可能要低得多。
来自: https://medium.com/checking-emptiness-in-distributed-objects/count-vs-isempty-surprised-to-see-the-impact-fa70c0246ee0
【讨论】:
所有这些都是糟糕的选择,花费几乎相同的时间 @PushpendraJaiswal 是的,在一个糟糕选择的世界里,我们应该选择最好的错误选择以上是关于如何检查火花数据框是不是为空?的主要内容,如果未能解决你的问题,请参考以下文章