现在,我必须使用df.count > 0来检查DataFrame是否为空。 但这效率很低。 有什么更好的方法吗?
谢谢。
PS:我想检查它是否为空,以便仅在DataFrame不为空时保存它
对于Spark 2.1.0,我的建议是将head(n: Int)或take(n: Int)与isEmpty一起使用,无论哪一个对您有最明确的意图。
1 2
| df.head(1).isEmpty
df.take(1).isEmpty |
与Python等效:
1 2
| 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。
1 2
| def first(): T = head()
def head(): T = head(1).head |
head(1)返回一个数组,因此在DataFrame为空时对该数组取head会导致java.util.NoSuchElementException。
1
| def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan) |
因此,与其直接调用head(),不如直接使用head(1)来获取数组,然后可以使用isEmpty。
take(n)也等同于head(n) ...
1
| def take(n: Int): Array[T] = head(n) |
并且limit(1).collect()等效于head(1)(在head(n: Int)方法中注意limit(n).queryExecution),因此以下内容都是等效的,至少从我的判断出发,并且您不必抓住java.util.NoSuchElementException DataFrame为空时发生异常。
1 2 3
| 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的执行计划做的事情很复杂,导致火花无法使用快捷方式。例如,如果您只是从镶木地板文件df = spark.read.parquet(...)中读取,我很确定spark将仅读取一个文件分区。但是,如果您的df正在执行其他操作(例如聚合),则可能会无意间迫使Spark读取和处理大部分(即使不是全部)源数据。
-
只是向AVOID报告我的经验:我天真地使用了df.limit(1).count()。在大型数据集上,它花费的时间比@ hulin003所报告的示例要多得多,这些示例几乎是瞬时的
-
关于此解决方案的一点说明:您应该避免在具有100列以上的数据帧上使用df.head(1).isEmpty或df.take(1).isEmpty,因为in会导致org.codehaus.janino.JaninoRuntimeException
我会说只是抓住底层的RDD。在Scala中:
在Python中:
话虽这么说,所有这一切都称为take(1).length,所以它会做与Rohan回答的相同的事情……也许稍微更明确些?
-
在我的情况下,这比df.count()== 0慢
-
将rdd转换为繁重的工作吗?
-
并不是的。在大多数情况下,RDD仍然是Spark一切的基础。
-
不要将df转换为RDD。它减慢了该过程。如果进行转换,它将整个DF转换为RDD,并检查其是否为空。想想如果DF有数百万行,转换到RDD本身会花费很多时间。
-
.rdd大大减慢了整个过程
-
如果在大数据帧上调用rdds isEmpty方法,它将极大地减慢其速度,尤其是在未缓存数据帧时。
您可以利用head()(或first())功能查看DataFrame是否具有单行。如果是这样,则它不是空的。
-
如果dataframe为空,则抛出" java.util.NoSuchElementException:空迭代器上的next"。 [火花1.3.1]
从Spark 2.4.0开始,存在Dataset.isEmpty。
它的实现是:
1 2 3 4
| def isEmpty: Boolean =
withAction("isEmpty", limit(1).groupBy().count().queryExecution) { plan =>
plan.executeCollect().head.getLong(0) == 0
} |
请注意,DataFrame不再是Scala中的类,而只是类型别名(可能在Spark 2.0中更改了):
1
| type DataFrame = Dataset[Row] |
-
isEmpty慢于df.head(1).isEmpty
-
@ Sandeep540真的吗?基准?您的建议至少实例化一行。 Spark实现只是传输一个数字。 head()也在使用limit(),groupBy()并没有做任何事情,需要获得一个RelationalGroupedDataset,后者再提供count()。因此,这应该不会明显变慢。如果数据集包含许多列(可能是非规范化的嵌套数据),则速度可能会更快。顺便说一句,你必须少键入:-)
对于Java用户,您可以在数据集上使用它:
1 2 3 4 5 6 7 8 9
| 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)并检查其是否为null。这将返回java.util.NoSuchElementException,因此最好尝试尝试df.take(1)。
完成take(1)而不是空行时,数据帧返回错误。我已经突出显示了引发错误的特定代码行。
-
如果在具有数百万条记录的海量数据帧上运行此方法,则count方法将需要一些时间。
-
我说的也一样,我不确定你为什么不赞成。
-
没错,您确实说了同样的话,很遗憾,我没有对您投反对票。
-
哦,好吧。对不起,TheMoos3,但无论您做什么,请注意答案并理解其概念。
-
当df为空时使用df.take(1)导致返回一个空ROW,该行无法与null进行比较
-
我在try / catch块中使用first()代替take(1),它可以正常工作
-
@LetsPlayYahtzee我用相同的运行和显示错误的图片更新了答案。 take(1)返回Array [Row]。并且当Array没有任何值时,默认情况下会给出ArrayOutOfBounds。因此,我认为它不会产生空行。我会说要观察并改变投票。
在Scala中,您可以使用隐式将isEmpty()和nonEmpty()方法添加到DataFrame API,这将使代码更易于阅读。
1 2 3 4 5 6 7 8 9
| 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._。之后,可以按如下方式直接使用这些方法:
1 2 3 4
| val df: DataFrame = ...
if (df.isEmpty) {
// Do something
} |
我有同样的问题,并且测试了3个主要解决方案:
df!= null df.count> 0
df.head(1).isEmpty()如@ hulin003建议
df.rdd.isEmpty @Justin Pihony建议
当然这3种有效,但是就性能而言,这是我在执行时间方面在我的机器的同一DF上执行这些方法时发现的:
大约需要9366ms
大约需要5607毫秒
大约需要1921ms
因此,我认为最好的解决方案是@Justin Pihony建议的df.rdd.isEmpty
-
选项3花费的时间更少,为什么要选择第二个?
-
糟糕,您的权利,我使用第3条,我更新了响应
在PySpark上,您也可以使用此bool(df.head(1))获得False值的True
如果数据框不包含任何行,则返回False
如果您使用的是Pypsark,则还可以执行以下操作:
我发现在某些情况下:
1 2 3 4 5
| >>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>
>>>df.take(1).isEmpty
'list' object has no attribute 'isEmpty' |
这与"长度"相同,或由head()替换take()
[解决方案]我们可以使用的问题。
1 2
| >>>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
take方法返回行数组,因此,如果数组大小等于零,则df中没有记录。
您可以这样做:
1 2 3 4 5
| 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)的引用。