Réponses:
Pour Spark 2.1.0, ma suggestion serait d'utiliser head(n: Int)
ou take(n: Int)
avec isEmpty
, celui qui a l'intention la plus claire pour vous.
df.head(1).isEmpty
df.take(1).isEmpty
avec l'équivalent Python:
len(df.head(1)) == 0 # or bool(df.head(1))
len(df.take(1)) == 0 # or bool(df.take(1))
Utiliser df.first()
et df.head()
renverra tous les deux le java.util.NoSuchElementException
si le DataFrame est vide. first()
appelle head()
directement, qui appelle head(1).head
.
def first(): T = head()
def head(): T = head(1).head
head(1)
renvoie un Array, donc prendre head
cet Array provoque le java.util.NoSuchElementException
lorsque le DataFrame est vide.
def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan)
Donc, au lieu d'appeler head()
, utilisez head(1)
directement pour obtenir le tableau et vous pouvez ensuite utiliser isEmpty
.
take(n)
équivaut également à head(n)
...
def take(n: Int): Array[T] = head(n)
Et limit(1).collect()
est équivalent à head(1)
(remarquez limit(n).queryExecution
dans la head(n: Int)
méthode), donc les éléments suivants sont tous équivalents, du moins d'après ce que je peux dire, et vous n'aurez pas à attraper une java.util.NoSuchElementException
exception lorsque le DataFrame est vide.
df.head(1).isEmpty
df.take(1).isEmpty
df.limit(1).collect().isEmpty
Je sais que c'est une question plus ancienne, donc j'espère qu'elle aidera quelqu'un à utiliser une version plus récente de Spark.
df.rdd.isEmpty
?
df.head(1)
prend beaucoup de temps, c'est probablement parce que votre df
plan d'exécution fait quelque chose de compliqué qui empêche Spark de prendre des raccourcis. Par exemple, si vous lisez simplement des fichiers parquet df = spark.read.parquet(...)
, je suis presque sûr que Spark ne lira qu'une seule partition de fichiers. Mais si vous df
faites d'autres choses comme des agrégations, vous pouvez forcer par inadvertance Spark à lire et à traiter une grande partie, sinon la totalité, de vos données sources.
df.limit(1).count()
naïvement. Sur les grands ensembles de données, cela prend beaucoup plus de temps que les exemples rapportés par @ hulin003 qui sont presque instantanés
Je dirais simplement de saisir le sous-jacent RDD
. Dans Scala:
df.rdd.isEmpty
en Python:
df.rdd.isEmpty()
Cela étant dit, tout cela ne fait qu'appeler take(1).length
, donc ça fera la même chose que Rohan a répondu ... juste peut-être un peu plus explicite?
Vous pouvez profiter des fonctions head()
(ou first()
) pour voir si le DataFrame
a une seule ligne. Si c'est le cas, il n'est pas vide.
Si vous le faites df.count > 0
. Il prend le décompte de toutes les partitions sur tous les exécuteurs et les additionne dans Driver. Cela prend un certain temps lorsque vous traitez des millions de lignes.
La meilleure façon de faire est d'effectuer df.take(1)
et de vérifier si sa valeur null. Cela reviendra java.util.NoSuchElementException
tellement mieux de faire un essai df.take(1)
.
Le dataframe renvoie une erreur quand take(1)
est terminé au lieu d'une ligne vide. J'ai mis en évidence les lignes de code spécifiques où cela génère l'erreur.
count
méthode prendra un certain temps.
Depuis Spark 2.4.0, il existe Dataset.isEmpty
.
def isEmpty: Boolean =
withAction("isEmpty", limit(1).groupBy().count().queryExecution) { plan =>
plan.executeCollect().head.getLong(0) == 0
}
Notez que a DataFrame
n'est plus une classe dans Scala, c'est juste un alias de type (probablement changé avec Spark 2.0):
type DataFrame = Dataset[Row]
Pour les utilisateurs Java, vous pouvez l'utiliser sur un ensemble de données:
public boolean isDatasetEmpty(Dataset<Row> ds) {
boolean isEmpty;
try {
isEmpty = ((Row[]) ds.head(1)).length == 0;
} catch (Exception e) {
return true;
}
return isEmpty;
}
Cela vérifie tous les scénarios possibles (vide, nul).
Dans Scala, vous pouvez utiliser des implicits pour ajouter les méthodes isEmpty()
et nonEmpty()
à l'API DataFrame, ce qui rendra le code un peu plus agréable à lire.
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
}
}
Ici, d'autres méthodes peuvent également être ajoutées. Pour utiliser la conversion implicite, utilisez import DataFrameExtensions._
dans le fichier que vous souhaitez utiliser la fonctionnalité étendue. Ensuite, les méthodes peuvent être utilisées directement comme suit:
val df: DataFrame = ...
if (df.isEmpty) {
// Do something
}
J'avais la même question, et j'ai testé 3 solutions principales:
et bien sûr les 3 fonctionnent, cependant en terme de performance, voici ce que j'ai trouvé, en exécutant ces méthodes sur le même DF dans ma machine, en terme de temps d'exécution:
donc je pense que la meilleure solution est df.rdd.isEmpty comme le suggère @Justin Pihony
J'ai trouvé cela sur certains cas:
>>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>
>>>df.take(1).isEmpty
'list' object has no attribute 'isEmpty'
c'est la même chose pour "length" ou remplacez take () par head ()
[Solution] pour le problème que nous pouvons utiliser.
>>>df.limit(2).count() > 1
False
Si vous utilisez Pypsark, vous pouvez également faire:
len(df.head(1)) > 0
dataframe.limit(1).count > 0
Cela déclenche également un travail, mais comme nous sélectionnons un enregistrement unique, même dans le cas d'un milliard d'enregistrements à l'échelle, la consommation de temps pourrait être beaucoup plus faible.
Vous pouvez le faire comme:
val df = sqlContext.emptyDataFrame
if( df.eq(sqlContext.emptyDataFrame) )
println("empty df ")
else
println("normal df")
schema
deux dataframes ( sqlContext.emptyDataFrame
& df
) soient identiques pour pouvoir revenir true
?
eq
est hérité de AnyRef
et teste si l'argument (that) est une référence à l'objet récepteur (this).