Jak sprawdzić, czy Spark Dataframe jest pusty?

102

W tej chwili muszę użyć, df.count > 0aby sprawdzić, czy DataFramejest pusty, czy nie. Ale jest to trochę nieefektywne. Czy jest lepszy sposób, aby to zrobić?

Dzięki.

PS: Chcę sprawdzić, czy jest pusty, aby zapisać tylko DataFramewtedy, gdy nie jest pusty

auxdx
źródło

Odpowiedzi:

155

W przypadku Spark 2.1.0 moja sugestia byłaby taka, aby użyć head(n: Int)lub take(n: Int)z isEmpty, w zależności od tego, który ma dla ciebie najwyraźniejszy zamiar.

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

z odpowiednikiem w Pythonie:

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

Użycie df.first()i df.head()zwróci, java.util.NoSuchElementExceptionjeśli DataFrame jest pusta. first()dzwoni head()bezpośrednio, co woła head(1).head.

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

head(1)zwraca Array, więc przyjęcie headtego Array powoduje java.util.NoSuchElementException, że DataFrame jest pusta.

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

Więc zamiast wywoływać head(), użyj head(1)bezpośrednio, aby uzyskać tablicę, a następnie możesz użyć isEmpty.

take(n)jest również równoważne z head(n)...

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

I limit(1).collect()jest równoważne head(1)(zauważ limit(n).queryExecutionw head(n: Int)metodzie), więc wszystkie poniższe są równoważne, przynajmniej z tego, co mogę powiedzieć, i nie będziesz musiał łapać java.util.NoSuchElementExceptionwyjątku, gdy DataFrame jest pusta.

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

Wiem, że jest to starsze pytanie, więc mam nadzieję, że pomoże to komuś korzystającemu z nowszej wersji Sparka.

hulin003
źródło
20
Dla osób używających pyspark. isEmpty nie jest rzeczą. Zamiast tego wykonaj len (d.head (1))> 0.
AntiPawn79
5
dlaczego tak jest lepiej df.rdd.isEmpty?
Dan Ciborowski - MSFT
1
df.head (1) .isEmpty zajmuje dużo czasu, czy istnieje jakieś inne zoptymalizowane rozwiązanie do tego.
Rakesh Sabbani
1
Hej @Rakesh Sabbani, Jeśli df.head(1)zajmuje to dużo czasu, prawdopodobnie wynika to z tego, że Twój dfplan wykonania robi coś skomplikowanego, co uniemożliwia iskierce pójście na skróty. Na przykład, jeśli czytasz tylko z plików parkietu df = spark.read.parquet(...), jestem prawie pewien, że Spark odczyta tylko jedną partycję plików. Ale jeśli dfrobisz inne rzeczy, takie jak agregacje, możesz nieumyślnie zmusić Spark do czytania i przetwarzania dużej części, jeśli nie wszystkich, danych źródłowych.
hulin003
tylko zgłaszam swoje doświadczenie UNIKAJ: df.limit(1).count()używałem naiwnie. W przypadku dużych zbiorów danych zajmuje to znacznie więcej czasu niż przykłady zgłoszone przez @ hulin003, które są prawie natychmiastowe
Vzzarr
45

Powiedziałbym, żeby po prostu złapać podstawę RDD. W Scali:

df.rdd.isEmpty

w Pythonie:

df.rdd.isEmpty()

Biorąc to pod uwagę, wszystko, co to robi, to wezwanie take(1).length, więc zrobi to samo, co odpowiedział Rohan ... tylko może trochę bardziej jednoznacznie?

Justin Pihony
źródło
6
Jest to zaskakująco wolniejsze niż df.count () == 0 w moim przypadku
architektoniczne
2
Czy przejście na rdd nie jest ciężkim zadaniem?
Alok
1
Nie całkiem. RDD nadal są podstawą wszystkiego, co Spark, w większości.
Justin Pihony,
28
Nie konwertuj df na RDD. Spowalnia proces. Jeśli przekonwertujesz, zamieni cały DF na RDD i sprawdzi, czy jest pusty. Pomyśl, że jeśli DF ma miliony wierszy, konwersja do samego RDD zajmuje dużo czasu.
Nandakishore
3
.rdd spowalnia proces tak bardzo, jak bardzo
Raul H
14

Możesz skorzystać z funkcji head()(lub first()), aby sprawdzić, czy DataFramema jeden wiersz. Jeśli tak, to nie jest pusty.

Rohan Aletty
źródło
10
jeśli dataframe jest pusta, generuje "java.util.NoSuchElementException: next na pustym iteratorze"; [Spark 1.3.1]
FelixHo
6

Jeśli tak df.count > 0. Bierze zliczenia wszystkich partycji we wszystkich wykonawcach i dodaje je do sterownika. Trwa to chwilę, gdy masz do czynienia z milionami wierszy.

Najlepszym sposobem, aby to zrobić, jest wykonanie df.take(1)i sprawdzenie, czy jego wartość jest zerowa. To wróci, java.util.NoSuchElementExceptionwięc lepiej spróbować df.take(1).

Dataframe zwraca błąd po zakończeniu take(1)zamiast pustego wiersza. Podkreśliłem konkretne wiersze kodu, w których zgłasza błąd.

wprowadź opis obrazu tutaj

Nandakishore
źródło
1
Jeśli uruchomisz to na ogromnej ramce danych z milionami rekordów, ta countmetoda zajmie trochę czasu.
TheM00s3
2
Powiedziałem to samo, nie jestem pewien, dlaczego opuściłeś kciuki.
Nandakishore
twoje prawo powiedziałeś to samo, niestety, nie przegłosowałem cię.
TheM00s3
Ooo dobrze. Przykro mi TheMoos3, ale ktokolwiek to zrobił, proszę zapoznać się z odpowiedzią i zrozumieć koncepcję.
Nandakishore
użycie df.take (1), gdy df jest puste, powoduje zwrócenie pustego ROW, którego nie można porównać z null
LetsPlayYahtzee
6

Od Spark 2.4.0 jest Dataset.isEmpty.

Jego implementacja to:

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

Zauważ, że a DataFramenie jest już klasą w Scali, to tylko alias typu (prawdopodobnie zmieniony w Spark 2.0):

type DataFrame = Dataset[Row]
Beryl
źródło
1
isEmpty jest wolniejsze niż df.head (1) .isEmpty
Sandeep540
@ Sandeep540 Naprawdę? Reper? Twoja propozycja tworzy instancję co najmniej jednego wiersza. Implementacja Spark po prostu przenosi liczbę. head () również używa limit (), groupBy () tak naprawdę nic nie robi, jest wymagane pobranie RelationalGroupedDataset, który z kolei zapewnia count (). Więc to nie powinno być znacznie wolniejsze. Prawdopodobnie jest to szybsze w przypadku zestawu danych, który zawiera wiele kolumn (prawdopodobnie zdenormalizowane dane zagnieżdżone). W każdym razie musisz pisać mniej :-)
Beryllium
5

W przypadku użytkowników języka Java możesz użyć tego w zestawie danych:

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

To sprawdź wszystkie możliwe scenariusze (puste, null).

Abdennacer Lachiheb
źródło
3

W Scali możesz użyć implicits, aby dodać metody isEmpty()i nonEmpty()do API DataFrame, co sprawi, że kod będzie nieco przyjemniejszy do czytania.

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

Tutaj można również dodać inne metody. Aby użyć niejawnej konwersji, użyj import DataFrameExtensions._w pliku, którego chcesz użyć rozszerzonej funkcjonalności. Następnie metody można zastosować bezpośrednio, tak jak:

val df: DataFrame = ...
if (df.isEmpty) {
  // Do something
}
Shaido - Przywróć Monikę
źródło
2

Miałem to samo pytanie i przetestowałem 3 główne rozwiązania:

  1. df! = null df.count> 0
  2. df.head (1) .isEmpty () zgodnie z sugestią @ hulin003
  3. df.rdd.isEmpty zgodnie z sugestią @Justin Pihony

i oczywiście te 3 prace, jednak pod względem wydajności, oto co znalazłem podczas wykonywania tych metod na tym samym DF w mojej maszynie, pod względem czasu wykonania:

  1. zajmuje to ~ 9366 ms
  2. zajmuje to ~ 5607 ms
  3. trwa ~ 1921 ms

dlatego uważam, że najlepszym rozwiązaniem jest df.rdd.isEmpty, jak sugeruje @Justin Pihony

imię
źródło
1
opcja 3 zajmuje mniej czasu, dlaczego druga?
thinkman
Ups, masz rację, używam trzeciego, aktualizuję odpowiedź
nazwa
z ciekawości ... z jakim rozmiarem DataFrames to testowano?
aiguofer
1

Zauważyłem, że w niektórych przypadkach:

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

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

to samo dotyczy „length” lub zamień take () na head ()

[Rozwiązanie] dla problemu, którego możemy użyć.

>>>df.limit(2).count() > 1
False
Shekhar Koirala
źródło
1

Jeśli korzystasz z Pypsark, możesz również:

len(df.head(1)) > 0
Adelholzener
źródło
1

Na PySpark, można również użyć tego bool(df.head(1))do uzyskania Trueod Falsewartości

Zwraca, Falsejeśli dataframe nie zawiera wierszy

Bose
źródło
0
df1.take(1).length>0

takeSposób powraca tablicę rzędach, tak, że rozmiar tablicy jest równa zero, nie ma rekordy df.

Gopi A
źródło
-1

dataframe.limit(1).count > 0

To również uruchamia pracę, ale ponieważ wybieramy pojedynczy rekord, nawet w przypadku miliardowych rekordów w skali zużycie czasu może być znacznie niższe.

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

Jordan Morris
źródło
Wszystko to są złe opcje, które zajmują prawie tyle samo czasu
Pushpendra Jaiswal
@PushpendraJaiswal tak, aw świecie złych opcji powinniśmy wybrać najlepszą złą opcję
Jordan Morris
-2

Możesz to zrobić tak:

val df = sqlContext.emptyDataFrame
if( df.eq(sqlContext.emptyDataFrame) )
    println("empty df ")
else 
    println("normal df")
SYer Wang
źródło
1
czy nie będzie wymagało, aby schemadwie ramki danych ( sqlContext.emptyDataFrame& df) były takie same, aby kiedykolwiek zostały zwrócone true?
y2k-shubham
1
To nie zadziała. eqjest dziedziczona z AnyRefi sprawdza, czy argument (that) jest odwołaniem do obiektu odbiornika (this).
Alper T. Turker,