Answers:
对于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.NoSuchElementException
DataFrame为空。
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
异常,当数据框为空。
df.head(1).isEmpty
df.take(1).isEmpty
df.limit(1).collect().isEmpty
我知道这是一个较旧的问题,因此希望它将对使用较新版本Spark的人有所帮助。
df.rdd.isEmpty
呢?
df.head(1)
要花费大量时间,可能是因为您df
的执行计划做的事情很复杂,导致spark无法采用快捷方式。例如,如果您只是从实木复合地板文件中读取df = spark.read.parquet(...)
,我敢肯定,spark只会读取一个文件分区。但是,如果您df
正在执行聚合之类的其他操作,则可能会无意间迫使Spark读取和处理大部分(如果不是全部)源数据。
df.limit(1).count()
天真。在大型数据集上,它花费的时间比@ hulin003所报告的示例几乎是即时的要
我会说只是抓住基础RDD
。在Scala中:
df.rdd.isEmpty
在Python中:
df.rdd.isEmpty()
话虽这么说,所有这一切都是call take(1).length
,所以它会做与Rohan回答的一样的事情……也许更明确一点?
从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]
对于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)。
如果可以的话df.count > 0
。它获取所有执行程序中所有分区的计数,并将其累加到Driver中。当您处理数百万行时,这需要一段时间。
最好的方法是执行df.take(1)
并检查其是否为空。这样可以java.util.NoSuchElementException
更好地进行尝试df.take(1)
。
完成后,数据框返回错误,take(1)
而不是空行。我已经突出显示了引发错误的特定代码行。
count
方法,则该方法将需要一些时间。
在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
}
我有同样的问题,并且测试了3个主要解决方案:
当然这3种有效,但是就性能而言,这是在执行时间方面在我的机器的同一DF上执行这些方法时发现的:
因此,我认为最好的解决方案是@Justin Pihony建议的df.rdd.isEmpty
我发现在某些情况下:
>>>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
dataframe.limit(1).count > 0
这也触发了工作,但是由于我们选择的是单条记录,即使是十亿规模的记录,时间消耗也可能更低。
来自:https : //medium.com/checking-emptiness-in-distributed-objects/count-vs-isempty-surprised-to-see-the-impact-fa70c0246ee0
您可以这样做:
val df = sqlContext.emptyDataFrame
if( df.eq(sqlContext.emptyDataFrame) )
println("empty df ")
else
println("normal df")
schema
两个数据帧(sqlContext.emptyDataFrame
&df
)相同才能返回true
?
eq
从继承AnyRef
并测试参数(that)是否是对接收者对象(this)的引用。