In questo momento, devo usare df.count > 0
per verificare se DataFrame
è vuoto o meno. Ma è un po 'inefficiente. C'è un modo migliore per farlo?
Grazie.
PS: voglio controllare se è vuoto in modo da salvare solo DataFrame
se non è vuoto
Risposte:
Per Spark 2.1.0, il mio suggerimento sarebbe quello di utilizzare head(n: Int)
o take(n: Int)
con isEmpty
, a seconda di quale ha l'intento più chiaro per te.
df.head(1).isEmpty
df.take(1).isEmpty
con l'equivalente Python:
len(df.head(1)) == 0 # or bool(df.head(1))
len(df.take(1)) == 0 # or bool(df.take(1))
L'uso di df.first()
e df.head()
restituirà entrambi java.util.NoSuchElementException
se il DataFrame è vuoto. first()
chiama head()
direttamente, che chiama head(1).head
.
def first(): T = head()
def head(): T = head(1).head
head(1)
restituisce un Array, quindi assumere quell'Array head
causa java.util.NoSuchElementException
quando il DataFrame è vuoto.
def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan)
Quindi, invece di chiamare head()
, usa head(1)
direttamente per ottenere l'array e poi puoi usare isEmpty
.
take(n)
è anche equivalente a head(n)
...
def take(n: Int): Array[T] = head(n)
Ed limit(1).collect()
è equivalente a head(1)
(nota limit(n).queryExecution
nel head(n: Int)
metodo), quindi i seguenti sono tutti equivalenti, almeno da quello che posso dire, e non dovrai catturare java.util.NoSuchElementException
un'eccezione quando il DataFrame è vuoto.
df.head(1).isEmpty
df.take(1).isEmpty
df.limit(1).collect().isEmpty
So che questa è una domanda precedente, quindi spero che aiuti qualcuno che utilizza una versione più recente di Spark.
df.rdd.isEmpty
?
df.head(1)
vuole molto tempo, probabilmente è perché il tuo df
piano di esecuzione sta facendo qualcosa di complicato che impedisce a Spark di prendere scorciatoie. Ad esempio, se stai leggendo solo da file parquet df = spark.read.parquet(...)
, sono abbastanza sicuro che Spark leggerà solo una partizione di file. Ma se df
stai facendo altre cose come le aggregazioni, potresti inavvertitamente forzare Spark a leggere ed elaborare una gran parte, se non tutti, dei tuoi dati di origine.
df.limit(1).count()
ingenuamente. Su grandi set di dati ci vuole molto più tempo rispetto agli esempi riportati da @ hulin003 che sono quasi istantanei
Direi di afferrare solo il sottostante RDD
. In Scala:
df.rdd.isEmpty
in Python:
df.rdd.isEmpty()
Detto questo, tutto ciò che fa è chiamare take(1).length
, quindi farà la stessa cosa che ha risposto Rohan ... solo forse un po 'più esplicito?
Puoi sfruttare le funzioni head()
(o first()
) per vedere se DataFrame
ha una singola riga. Se è così, non è vuoto.
Se lo fai df.count > 0
. Prende il conteggio di tutte le partizioni su tutti gli esecutori e le somma in Driver. Questo richiede un po 'di tempo quando hai a che fare con milioni di righe.
Il modo migliore per farlo è eseguire df.take(1)
e controllare se è nullo. Questo tornerà java.util.NoSuchElementException
quindi meglio provare df.take(1)
.
Il dataframe restituisce un errore quando take(1)
viene eseguito invece di una riga vuota. Ho evidenziato le righe di codice specifiche in cui genera l'errore.
count
metodo richiederà del tempo.
A partire da Spark 2.4.0 esiste Dataset.isEmpty
.
La sua implementazione è:
def isEmpty: Boolean =
withAction("isEmpty", limit(1).groupBy().count().queryExecution) { plan =>
plan.executeCollect().head.getLong(0) == 0
}
Nota che a DataFrame
non è più una classe in Scala, è solo un alias di tipo (probabilmente modificato con Spark 2.0):
type DataFrame = Dataset[Row]
Per gli utenti Java puoi usarlo su un set di dati:
public boolean isDatasetEmpty(Dataset<Row> ds) {
boolean isEmpty;
try {
isEmpty = ((Row[]) ds.head(1)).length == 0;
} catch (Exception e) {
return true;
}
return isEmpty;
}
Questo controlla tutti i possibili scenari (vuoto, nullo).
In Scala puoi usare gli impliciti per aggiungere i metodi isEmpty()
e nonEmpty()
l'API DataFrame, che renderà il codice un po 'più piacevole da leggere.
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
}
}
Qui possono essere aggiunti anche altri metodi. Per utilizzare la conversione implicita, utilizza import DataFrameExtensions._
nel file che desideri utilizzare la funzionalità estesa. Successivamente, i metodi possono essere utilizzati direttamente in questo modo:
val df: DataFrame = ...
if (df.isEmpty) {
// Do something
}
Ho avuto la stessa domanda e ho testato 3 soluzioni principali:
e ovviamente i 3 funzionano, comunque in termini di perfermance, ecco cosa ho trovato, eseguendo questi metodi sullo stesso DF della mia macchina, in termini di tempo di esecuzione:
quindi penso che la soluzione migliore sia df.rdd.isEmpty come suggerisce @Justin Pihony
Ho scoperto che in alcuni casi:
>>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>
>>>df.take(1).isEmpty
'list' object has no attribute 'isEmpty'
questo è lo stesso per "length" o sostituisci take () con head ()
[Soluzione] per il problema che possiamo utilizzare.
>>>df.limit(2).count() > 1
False
Se stai usando Pypsark, potresti anche fare:
len(df.head(1)) > 0
dataframe.limit(1).count > 0
Anche questo innesca un lavoro, ma poiché stiamo selezionando un singolo record, anche in caso di miliardi di record di scala il consumo di tempo potrebbe essere molto inferiore.
Puoi farlo come:
val df = sqlContext.emptyDataFrame
if( df.eq(sqlContext.emptyDataFrame) )
println("empty df ")
else
println("normal df")
schema
due dataframe ( sqlContext.emptyDataFrame
& df
) siano uguali per tornare mai true
?
eq
viene ereditato da AnyRef
e verifica se l'argomento (that) è un riferimento all'oggetto ricevente (this).