【发布时间】:2015-12-18 21:14:30
【问题描述】:
现在,我必须使用df.count > 0 来检查DataFrame 是否为空。但这有点低效。有没有更好的方法来做到这一点?
PS:我想检查它是否为空,所以我只保存DataFrame,如果它不为空
【问题讨论】:
标签: apache-spark pyspark apache-spark-sql
现在,我必须使用df.count > 0 来检查DataFrame 是否为空。但这有点低效。有没有更好的方法来做到这一点?
PS:我想检查它是否为空,所以我只保存DataFrame,如果它不为空
【问题讨论】:
标签: apache-spark pyspark apache-spark-sql
对于 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 的人有所帮助。
【讨论】:
df.rdd.isEmpty更好?
df.head(1) 花费大量时间,那可能因为您的df 的执行计划正在执行一些复杂的事情,从而阻止了火花从走捷径。例如,如果你只是从 parquet 文件中读取,df = spark.read.parquet(...),我很确定 spark 只会读取一个文件分区。但是,如果您的 df 正在执行其他操作,例如聚合,您可能会无意中强制 spark 读取和处理大部分(如果不是全部)源数据。
df.limit(1).count()。在大型数据集上,它比@hulin003 报告的示例花费更多的时间,这些示例几乎是瞬时的
我会说只是抓住底层RDD。在 Scala 中:
df.rdd.isEmpty
在 Python 中:
df.rdd.isEmpty()
话虽如此,这只是调用take(1).length,所以它会做与Rohan回答相同的事情......只是可能稍微更明确一点?
【讨论】:
我有同样的问题,我测试了 3 个主要解决方案:
(df != null) && (df.count > 0)df.head(1).isEmpty() @hulin003 建议df.rdd.isEmpty() @Justin Pihony 建议当然,这 3 种方法都有效,但是就性能而言,这是我发现的,当在我的机器上的同一个 DF 上执行这些方法时,就执行时间而言:
因此我认为最好的解决方案是 df.rdd.isEmpty() @Justin Pihony 建议
【讨论】:
从 Spark 2.4.0 开始有Dataset.isEmpty。
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]
【讨论】:
您可以利用head()(或first())函数来查看DataFrame 是否只有一行。如果是,则不为空。
【讨论】:
【讨论】:
count 方法将需要一些时间。
对于 Java 用户,您可以在数据集上使用它:
public boolean isDatasetEmpty(Dataset<Row> ds) {
boolean isEmpty;
try {
isEmpty = ((Row[]) ds.head(1)).length == 0;
} catch (Exception e) {
return true;
}
return isEmpty;
}
这会检查所有可能的情况(空、空)。
【讨论】:
在 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
}
【讨论】:
在 PySpark 上,您还可以使用此 bool(df.head(1)) 来获取 True 的 False 值
如果数据框不包含任何行,则返回 False
【讨论】:
如果你使用 Pyspark,你也可以这样做:
len(df.head(1)) > 0
【讨论】:
我发现在某些情况下:
>>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>
>>>df.take(1).isEmpty
'list' object has no attribute 'isEmpty'
"length" 也一样,或者用 head() 替换 take()
[解决方案]我们可以使用的问题。
>>>df.limit(2).count() > 1
False
【讨论】:
在 Spark 2.4 版中引入了 DataFrames 的 isEmpty() 方法。因此,在任何版本的 spark 2.4 或更高版本上检查 DataFrame 是否为空的最佳方法是使用函数 isEmpty()
df.isEmpty()
【讨论】:
df1.take(1).length>0
take 方法返回行数组,因此如果数组大小为零,则df 中没有记录。
【讨论】:
假设我们有以下空数据框:
df = spark.sql("show tables").limit(0)
如果您使用的是 Spark 2.1,对于 pyspark,要检查此数据框是否为空,您可以使用:
df.count() > 0
或者
bool(df.head(1))
【讨论】:
你可以这样做:
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) 的引用。
dataframe.limit(1).count > 0
这也会触发作业,但由于我们选择的是单个记录,因此即使在十亿规模记录的情况下,时间消耗也可能要低得多。
【讨论】: