Как проверить, пуст ли фрейм данных искры?


102

Прямо сейчас я должен использовать, df.count > 0чтобы проверить DataFrame, пуст или нет. Но это неэффективно. Есть ли лучший способ сделать это?

Спасибо.

PS: я хочу проверить, пуст ли он, чтобы я сохранял только, DataFrameесли он не пустой

Ответы:


155

Для 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.NoSuchElementExceptionесли 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.


20
Для тех, кто использует pyspark. isEmpty - это не вещь. Вместо этого сделайте len (d.head (1))> 0.
AntiPawn79

5
почему тогда это лучше df.rdd.isEmpty?
Дэн Циборовски - MSFT

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

1
Привет, @Rakesh Sabbani! Если на df.head(1)это уходит много времени, возможно , это потому, что в вашем dfплане выполнения есть что-то сложное, что не позволяет Spark использовать ярлыки. Например, если вы просто читаете паркетные файлы df = spark.read.parquet(...), я уверен, что Spark будет читать только один файловый раздел. Но если вы dfделаете другие вещи, такие как агрегирование, вы можете непреднамеренно заставить Spark читать и обрабатывать большую часть, если не все, ваших исходных данных.
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 01

3
.rdd настолько сильно замедляет процесс, как сильно
Raul H

14

Вы можете воспользоваться функциями head()(или first()), чтобы узнать, есть ли у DataFrameних одна строка. Если так, то он не пустой.


10
если фрейм данных пуст, он выбрасывает «java.util.NoSuchElementException: next на пустом итераторе»; [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 приводит к возврату пустой ROW, которую нельзя сравнивать с 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! = null df.count> 0
  2. df.head (1) .isEmpty () как @ hulin003 предлагает
  3. df.rdd.isEmpty, как предлагает @Justin Pihony

и, конечно же, эти 3 работы, однако с точки зрения перферманса, вот что я обнаружил при выполнении этих методов на одном и том же DF на моей машине во время выполнения:

  1. занимает ~ 9366 мс
  2. занимает ~ 5607 мс
  3. это занимает ~ 1921 мс

поэтому я думаю, что лучшим решением является df.rdd.isEmpty, как предлагает @Justin Pihony


1
вариант 3 занимает меньше времени, почему второй?
thinkman

Ой, правильно, я использую 3-й, обновляю ответ
aName

из любопытства ... с каким размером DataFrames это тестировалось?
aiguofer

1

Я обнаружил, что в некоторых случаях:

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

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

это то же самое для "length" или заменить 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.