Wie überprüfe ich, ob der Funken-Datenrahmen leer ist?


99

Im Moment muss ich df.count > 0überprüfen, ob das DataFrameleer ist oder nicht. Aber es ist irgendwie ineffizient. Gibt es einen besseren Weg, das zu tun?

Vielen Dank.

PS: Ich möchte überprüfen, ob es leer ist, damit ich das nur speichere, DataFramewenn es nicht leer ist

Antworten:


153

Für Spark 2.1.0 würde ich vorschlagen, head(n: Int)oder take(n: Int)mit zu verwenden isEmpty, je nachdem, was für Sie die klarste Absicht ist.

df.head(1).isEmpty
df.take(1).isEmpty

mit Python-Äquivalent:

len(df.head(1)) == 0  # or bool(df.head(1))
len(df.take(1)) == 0  # or bool(df.take(1))

Mit df.first()und df.head()geben beide zurück, java.util.NoSuchElementExceptionwenn der DataFrame leer ist. first()ruft head()direkt an, was anruft head(1).head.

def first(): T = head()
def head(): T = head(1).head

head(1)Gibt ein Array zurück. Wenn Sie headdieses Array java.util.NoSuchElementExceptionübernehmen, ist der DataFrame leer.

def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan)

Anstatt also aufzurufen head(), verwenden Sie head(1)direkt, um das Array abzurufen, und dann können Sie es verwenden isEmpty.

take(n)ist auch gleichbedeutend mit head(n)...

def take(n: Int): Array[T] = head(n)

Und limit(1).collect()ist äquivalent zu head(1)(Hinweis limit(n).queryExecutionin der head(n: Int)Methode), daher sind alle folgenden äquivalent, zumindest soweit ich java.util.NoSuchElementExceptiondas beurteilen kann, und Sie müssen keine Ausnahme abfangen, wenn der DataFrame leer ist.

df.head(1).isEmpty
df.take(1).isEmpty
df.limit(1).collect().isEmpty

Ich weiß, dass dies eine ältere Frage ist. Hoffentlich hilft sie jemandem, der eine neuere Version von Spark verwendet.


19
Für diejenigen, die pyspark nutzen. isEmpty ist keine Sache. Führen Sie stattdessen len (d.head (1))> 0 aus.
AntiPawn79

3
Warum ist dies besser dann df.rdd.isEmpty?
Dan Ciborowski - MSFT

1
df.head (1) .isEmpty nimmt viel Zeit in Anspruch. Gibt es dafür eine andere optimierte Lösung?
Rakesh Sabbani

1
Hey @Rakesh Sabbani, wenn df.head(1)es viel Zeit in Anspruch nimmt, liegt es wahrscheinlich daran, dass Ihr dfAusführungsplan etwas Kompliziertes tut, das verhindert, dass Funken Verknüpfungen verwenden. Wenn Sie beispielsweise nur aus Parkettdateien lesen df = spark.read.parquet(...), bin ich mir ziemlich sicher, dass spark nur eine Dateipartition liest. Wenn Sie dfjedoch andere Dinge wie Aggregationen ausführen, erzwingen Sie möglicherweise versehentlich den Funken, einen großen Teil, wenn nicht alle Ihrer Quelldaten zu lesen und zu verarbeiten.
hulin003

Ich habe nur meine Erfahrungen an AVOID gemeldet: Ich habe df.limit(1).count()naiv verwendet. Bei großen Datenmengen dauert es viel länger als bei den von @ hulin003 gemeldeten Beispielen, die fast augenblicklich sind
Vzzarr

44

Ich würde sagen, nur den Basiswert zu ergreifen RDD. In Scala:

df.rdd.isEmpty

in Python:

df.rdd.isEmpty()

Davon abgesehen ist alles, was dies tut, ein Anruf take(1).length, also wird es das Gleiche tun, wie Rohan geantwortet hat ... nur vielleicht etwas expliziter?


6
Dies ist überraschend langsamer als df.count () == 0 in meinem Fall
Architektur

2
Ist das Konvertieren in rdd nicht eine schwere Aufgabe?
Alok

1
Nicht wirklich. RDDs sind immer noch die Grundlage für alles, was Spark zum größten Teil ausmacht.
Justin Pihony

28
Konvertieren Sie den df nicht in RDD. Es verlangsamt den Prozess. Wenn Sie konvertieren, wird der gesamte DF in RDD konvertiert und überprüft, ob er leer ist. Wenn DF Millionen von Zeilen hat, nimmt die Konvertierung in RDD selbst viel Zeit in Anspruch.
Nandakishore

3
.rdd verlangsamt den Prozess so sehr wie viel
Raul H

14

Sie können die head()(oder first()) Funktionen nutzen, um festzustellen, ob das DataFrameeine einzelne Zeile hat. Wenn ja, ist es nicht leer.


10
Wenn der Datenrahmen leer ist, wird "java.util.NoSuchElementException: next on empty iterator" ausgelöst. [Spark 1.3.1]
FelixHo

6

Seit Spark 2.4.0 gibt es Dataset.isEmpty.

Die Implementierung ist:

def isEmpty: Boolean = 
  withAction("isEmpty", limit(1).groupBy().count().queryExecution) { plan =>
    plan.executeCollect().head.getLong(0) == 0
}

Beachten Sie, dass a DataFramein Scala keine Klasse mehr ist, sondern nur ein Typalias (wahrscheinlich mit Spark 2.0 geändert):

type DataFrame = Dataset[Row]

1
isEmpty ist langsamer als df.head (1) .isEmpty
Sandeep540

@ Sandeep540 Wirklich? Benchmark? Ihr Vorschlag instanziiert mindestens eine Zeile. Die Spark-Implementierung transportiert nur eine Nummer. head () verwendet ebenfalls limit (), groupBy () tut eigentlich nichts, es ist erforderlich, ein RelationalGroupedDataset abzurufen, das wiederum count () bereitstellt. Das sollte also nicht wesentlich langsamer sein. Es ist wahrscheinlich schneller bei einem Datensatz, der viele Spalten enthält (möglicherweise denormalisierte verschachtelte Daten). Immer muss man weniger tippen :-)
Beryllium

5

Für Java-Benutzer können Sie dies für einen Datensatz verwenden:

public boolean isDatasetEmpty(Dataset<Row> ds) {
        boolean isEmpty;
        try {
            isEmpty = ((Row[]) ds.head(1)).length == 0;
        } catch (Exception e) {
            return true;
        }
        return isEmpty;
}

Dies überprüft alle möglichen Szenarien (leer, null).


5

Wenn du das tust df.count > 0. Es zählt die Anzahl aller Partitionen aller Executoren und addiert sie bei Driver. Dies kann eine Weile dauern, wenn Sie mit Millionen von Zeilen arbeiten.

Der beste Weg, dies zu tun, besteht darin, durchzuführen df.take(1)und zu überprüfen, ob es null ist. Dies wird java.util.NoSuchElementExceptionso besser zurückkehren, um es zu versuchen df.take(1).

Der Datenrahmen gibt einen Fehler zurück, wenn take(1)er anstelle einer leeren Zeile ausgeführt wird. Ich habe die spezifischen Codezeilen hervorgehoben, in denen der Fehler ausgelöst wird.

Geben Sie hier die Bildbeschreibung ein


1
Wenn Sie dies auf einem massiven Datenrahmen mit Millionen von Datensätzen ausführen, wird diese countMethode einige Zeit in Anspruch nehmen.
TheM00s3

2
Ich sagte dasselbe, ich bin mir nicht sicher, warum du einen Daumen runter gegeben hast.
Nandakishore

Ihr Recht, Sie haben dasselbe gesagt, leider habe ich Sie nicht abgelehnt.
TheM00s3

Ohhh okay. Es tut mir leid, TheMoos3, aber wer auch immer es getan hat, bitte beachten Sie die Antwort und verstehen Sie das Konzept.
Nandakishore

Die Verwendung von df.take (1), wenn der df leer ist, führt dazu, dass eine leere REIHE zurückgegeben wird, die nicht mit null verglichen werden kann
LetsPlayYahtzee

3

In Scala können Sie Implicits verwenden, um die Methoden isEmpty()und nonEmpty()die DataFrame-API hinzuzufügen, wodurch der Code ein bisschen besser lesbar wird.

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
  }
}

Hier können auch andere Methoden hinzugefügt werden. Verwenden Sie import DataFrameExtensions._in der Datei , in der Sie die erweiterte Funktionalität verwenden möchten, die implizite Konvertierung . Danach können die Methoden direkt wie folgt verwendet werden:

val df: DataFrame = ...
if (df.isEmpty) {
  // Do something
}

2

Ich hatte die gleiche Frage und habe 3 Hauptlösungen getestet:

  1. df! = null df.count> 0
  2. df.head (1) .isEmpty () wie @ hulin003 vermuten lässt
  3. df.rdd.isEmpty, wie @Justin Pihony vorschlägt

und natürlich funktionieren die 3, jedoch in Bezug auf die Leistung, hier ist, was ich gefunden habe, als ich diese Methoden auf demselben DF in meinem Computer in der Laufzeit der Ausführungszeit ausführte:

  1. es dauert ~ 9366ms
  2. es dauert ~ 5607ms
  3. es dauert ~ 1921ms

Daher denke ich, dass die beste Lösung df.rdd.isEmpty ist, wie @Justin Pihony vorschlägt


1
Option 3 braucht weniger Zeit, warum die zweite?
Thinkman

Hoppla, dein Recht, ich benutze den 3., ich aktualisiere die Antwort
aName

aus Neugier ... mit welcher Größe wurden DataFrames getestet?
Aiguofer

1

Ich fand das in einigen Fällen:

>>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>

>>>df.take(1).isEmpty
'list' object has no attribute 'isEmpty'

Dies gilt auch für "Länge" oder ersetzen Sie take () durch head ()

[Lösung] für das Problem, das wir verwenden können.

>>>df.limit(2).count() > 1
False

1

Wenn Sie Pypsark verwenden, können Sie auch Folgendes tun:

len(df.head(1)) > 0

1

Auf PySpark, können Sie auch diese verwenden bool(df.head(1))ein erhalten Truevon FalseWert

Es wird zurückgegeben, Falsewenn der Datenrahmen keine Zeilen enthält


0
df1.take(1).length>0

Die takeMethode gibt das Zeilenarray zurück. Wenn also die Arraygröße gleich Null ist, sind keine Datensätze vorhanden df.


-1

dataframe.limit(1).count > 0

Dies löst auch einen Job aus, aber da wir einen einzelnen Datensatz auswählen, könnte der Zeitverbrauch selbst bei Datensätzen im Milliardenmaßstab viel geringer sein.

Von: https://medium.com/checking-emptiness-in-distributed-objects/count-vs-isempty-surprised-to-see-the-impact-fa70c0246ee0


All dies sind schlechte Optionen, die fast die gleiche Zeit in
Anspruch

@PushpendraJaiswal Ja, und in einer Welt voller schlechter Optionen sollten wir die beste schlechte Option wählen
Jordan Morris

-2

Sie können es wie folgt machen:

val df = sqlContext.emptyDataFrame
if( df.eq(sqlContext.emptyDataFrame) )
    println("empty df ")
else 
    println("normal df")

1
Wird es nicht erforderlich sein, dass der schemavon zwei Datenrahmen ( sqlContext.emptyDataFrame& df) gleich ist, um jemals zurückzukehren true?
y2k-shubham

1
Das wird nicht funktionieren. eqwird von geerbt AnyRefund prüft, ob das Argument (das) eine Referenz auf das Empfängerobjekt (das) ist.
Alper t. Turker
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.