In questo momento, devo usare df.count > 0per 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 DataFramese 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.NoSuchElementExceptionse 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 headcausa java.util.NoSuchElementExceptionquando 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).queryExecutionnel head(n: Int)metodo), quindi i seguenti sono tutti equivalenti, almeno da quello che posso dire, e non dovrai catturare java.util.NoSuchElementExceptionun'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 dfpiano 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 dfstai 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 DataFrameha 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.NoSuchElementExceptionquindi 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.
countmetodo 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 DataFramenon è 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")
schemadue dataframe ( sqlContext.emptyDataFrame& df) siano uguali per tornare mai true?
eqviene ereditato da AnyRefe verifica se l'argomento (that) è un riferimento all'oggetto ricevente (this).