Як перевірити, чи кадр даних spark не порожній?


101

Зараз я повинен використовувати, df.count > 0щоб перевірити, чи DataFrameпорожній чи ні. Але це наче неефективно. Чи є кращий спосіб це зробити?

Дякую.

PS: Я хочу перевірити, чи не пусте, щоб зберегти лише DataFrameякщо не пусте

Відповіді:


154

Що стосується Spark 2.1.0, то я б запропонував використовувати head(n: Int)або take(n: Int)з isEmpty, незалежно від того, хто з вас має найбільш чіткий намір.

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

з еквівалентом Python:

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

Використання df.first()і df.head()поверне значення java.util.NoSuchElementExceptionif, якщо DataFrame порожній. first()дзвінки head()безпосередньо, які дзвінки head(1).head.

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

head(1)повертає масив, тому прийняття headцього масиву викликає, java.util.NoSuchElementExceptionколи DataFrame порожній.

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

Тому замість дзвінка head()використовуйте head(1)безпосередньо для отримання масиву, а потім можете використовувати isEmpty.

take(n)також еквівалентно head(n)...

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

І limit(1).collect()еквівалентно head(1)(зауважте limit(n).queryExecutionу head(n: Int)методі), тому всі наведені нижче еквівалентні, принаймні з того, що я можу сказати, і вам не доведеться ловити java.util.NoSuchElementExceptionвиняток, коли DataFrame порожній.

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

Я знаю, що це давнє запитання, тому, сподіваюся, це допоможе комусь, хто використовує новішу версію Spark.


19
Для тих, хто використовує піспарк. isEmpty - це не річ. Замість цього зробіть len (d.head (1))> 0.
AntiPawn79,

5
чому це краще тоді df.rdd.isEmpty?
Ден Циборовський - MSFT

1
df.head (1) .isEmpty займає величезний час, чи є для цього якесь інше оптимізоване рішення.
Ракеш Саббані,

1
Привіт, @Rakesh Sabbani, якщо df.head(1)це забирає багато часу, це, мабуть, тому, що ваш dfплан виконання робить щось складне, що заважає іскрі приймати ярлики. Наприклад, якщо ви просто читаєте з паркетних файлів df = spark.read.parquet(...), я впевнений, що іскра буде читати лише один розділ файлу. Але якщо ви dfробите інші речі, такі як агрегації, ви можете ненавмисно змусити іскру читати та обробляти значну частину, якщо не всіх, ваших вихідних даних.
hulin003

просто повідомляючи про свій досвід УНИКНУТИ: я користувався df.limit(1).count()наївно. На великих наборах даних це займає набагато більше часу, ніж наведені приклади @ hulin003, які майже миттєві
Vzzarr,

45

Я б сказав, щоб просто схопити основне RDD. У Scala:

df.rdd.isEmpty

в Python:

df.rdd.isEmpty()

З take(1).lengthогляду на це, все це робить виклик , тож буде робити те саме, що відповів Рохан ... лише, можливо, трохи більш чітко?


6
Це напрочуд повільніше, ніж df.count () == 0 у моєму випадку
архітектонічний

2
Чи не перетворення на rdd важке завдання?
Alok

1
Не зовсім. RDD все ще є основою всього Spark здебільшого.
Джастін Піхоні

28
Не перетворюйте df на RDD. Це уповільнює процес. Якщо ви конвертуєте, він перетворить весь DF на RDD і перевірте, чи він порожній. Подумайте, якщо у DF мільйони рядків, потрібно багато часу для перетворення на сам RDD.
Nandakishore

3
.rdd настільки гальмує процес, як багато
Raul H,

14

Ви можете скористатися перевагами head()(або first()) функцій, щоб побачити, чи DataFrameє в одному рядку. Якщо так, це не пусте.


10
якщо кадр даних порожній, він видає "java.util.NoSuchElementException: наступний на порожньому ітераторі"; [Spark 1.3.1]
FelixHo

6

Якщо ви це зробите df.count > 0. Він бере підрахунок усіх розділів у всіх виконавцях і додає їх у Driver. Це займає деякий час, коли ви маєте справу з мільйонами рядків.

Найкращий спосіб зробити це - виконати df.take(1)та перевірити, чи є він нульовим. Це повернеться, java.util.NoSuchElementExceptionтак що краще спробувати df.take(1).

Коли виконано, кадр даних повертає помилку take(1)замість порожнього рядка. Я виділив конкретні рядки коду, де він видає помилку.

введіть тут опис зображення


1
якщо ви запускаєте це на масивному фреймі даних з мільйонами записів, цей countметод займе деякий час.
TheM00s3

2
Я сказав те саме, я не впевнений, чому ти дав великі пальці.
Nandakishore

Ваше право, ви сказали те саме, на жаль, я вас не підтримав.
TheM00s3

Ох, добре. Мені шкода TheMoos3, але хто б це не зробив, будь ласка, дотримуйтесь відповіді та зрозумійте концепцію.
Nandakishore

використання df.take (1), коли df порожній, призводить до повернення порожнього РЯДУ, який неможливо порівняти з null
LetsPlayYahtzee

6

З Spark 2.4.0 існує Dataset.isEmpty.

Його реалізація :

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

Зверніть увагу, що a DataFrameбільше не є класом у Scala, це просто псевдонім типу (можливо, змінений із Spark 2.0):

type DataFrame = Dataset[Row]

1
isEmpty повільніше, ніж df.head (1) .isEmpty
Sandeep540

@ Sandeep540 Справді? Тест? Ваша пропозиція створює принаймні один рядок. Реалізація Spark просто транспортує число. head () також використовує limit (), groupBy () насправді нічого не робить, потрібно отримати RelationalGroupedDataset, який, у свою чергу, забезпечує count (). Тож це не повинно бути значно повільніше. Можливо, це швидше у випадку набору даних, який містить багато стовпців (можливо, денормалізовані вкладені дані). В іншому випадку вам доведеться набирати менше :-)
Берилій,

5

Для користувачів Java ви можете використовувати це на наборі даних:

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

Це перевіряє всі можливі сценарії (порожній, нульовий).


3

У Scala ви можете використовувати імпліцити для додавання методів isEmpty()та nonEmpty()до API DataFrame, що зробить код трохи приємнішим для читання.

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

Тут можна додати й інші методи. Щоб використовувати неявне перетворення, використовуйте import DataFrameExtensions._у файлі, який потрібно використовувати, розширену функціональність. Згодом методи можна використовувати безпосередньо так:

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

2

У мене було те саме питання, і я протестував 3 основні рішення:

  1. df! = нуль df.count> 0
  2. df.head (1) .isEmpty (), як пропонує @ hulin003
  3. df.rdd.isПорожньо, як пропонує @Justin Pihony

і, звичайно, 3 роботи, однак з точки зору виконання, ось що я виявив, виконуючи ці методи на тому самому DF в моїй машині, в термін виконання:

  1. це займає ~ 9366 мс
  2. це займає ~ 5607мс
  3. це займає ~ 1921мс

тому я думаю, що найкращим рішенням є df.rdd.isEmpty, як пропонує @Justin Pihony


1
варіант 3 займає менше часу, чому другий?
мислитель

Ой, право, я використовую 3-ту, я
оновлюю

з цікавості ... якого розміру DataFrames тестували?
aiguofer

1

Я виявив, що в деяких випадках:

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

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

це те саме для "довжини" або замініть take () на head ()

[Рішення] для проблеми, яку ми можемо використати.

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


1

На PySpark, ви також можете використовувати це bool(df.head(1))для отримання TrueзFalse значення

Він повертається, Falseякщо фрейм даних не містить рядків


0
df1.take(1).length>0

takeМетод повертає масив рядків, так що якщо розмір масиву дорівнює нулю, немає записів в df.


-1

dataframe.limit(1).count > 0

Це також запускає роботу, але оскільки ми вибираємо єдиний запис, навіть у випадку мільярдових записів масштабу споживання часу може бути набагато меншим.

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


Все це погані варіанти, що займають майже однаковий час
Пушпендра Джайсваль,

@PushpendraJaiswal так, і у світі поганих варіантів нам слід вибрати найкращий поганий варіант
Джордан Морріс

-2

Ви можете зробити це так:

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

1
чи не буде потрібно, щоб schemaдва кадри даних ( sqlContext.emptyDataFrame& df) були однаковими, щоб колись повернутися true?
y2k-shubham

1
Це не спрацює. eqуспадковується від AnyRefі перевіряє, чи аргумент (that) є посиланням на об'єкт одержувача (this).
Альпер т. Turker
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.