Respostas:
Para o Spark 2.1.0, minha sugestão seria usar head(n: Int)
ou take(n: Int)
com isEmpty
, o que tiver a intenção mais clara para você.
df.head(1).isEmpty
df.take(1).isEmpty
com Python equivalente:
len(df.head(1)) == 0 # or bool(df.head(1))
len(df.take(1)) == 0 # or bool(df.take(1))
Usar df.first()
e df.head()
retornará o java.util.NoSuchElementException
se o DataFrame estiver vazio. first()
liga head()
diretamente, que liga head(1).head
.
def first(): T = head()
def head(): T = head(1).head
head(1)
retorna um Array, portanto, assumir head
esse Array causa o java.util.NoSuchElementException
quando o DataFrame está vazio.
def head(n: Int): Array[T] = withAction("head", limit(n).queryExecution)(collectFromPlan)
Portanto, em vez de chamar head()
, use head(1)
diretamente para obter o array e, em seguida, você pode usar isEmpty
.
take(n)
também é equivalente a head(n)
...
def take(n: Int): Array[T] = head(n)
E limit(1).collect()
é equivalente a head(1)
(observe limit(n).queryExecution
no head(n: Int)
método), então java.util.NoSuchElementException
os itens a seguir são todos equivalentes, pelo menos pelo que eu posso dizer, e você não terá que pegar uma exceção quando o DataFrame estiver vazio.
df.head(1).isEmpty
df.take(1).isEmpty
df.limit(1).collect().isEmpty
Eu sei que esta é uma pergunta mais antiga, então espero que ajude alguém que está usando uma versão mais recente do Spark.
df.rdd.isEmpty
?
df.head(1)
está demorando muito, provavelmente é porque seu df
plano de execução está fazendo algo complicado que impede o Spark de pegar atalhos. Por exemplo, se você está apenas lendo arquivos do parquet df = spark.read.parquet(...)
, tenho certeza que o spark lerá apenas uma partição do arquivo. Mas se você df
está fazendo outras coisas como agregações, pode estar forçando inadvertidamente o Spark a ler e processar uma grande parte, se não todos, de seus dados de origem.
df.limit(1).count()
ingenuamente. Em grandes conjuntos de dados, leva muito mais tempo do que os exemplos relatados por @ hulin003 que são quase instantâneos
Eu diria apenas para pegar o subjacente RDD
. Em Scala:
df.rdd.isEmpty
em Python:
df.rdd.isEmpty()
Dito isso, tudo que isso faz é ligar take(1).length
, então fará a mesma coisa que Rohan respondeu ... apenas talvez um pouco mais explícito?
Você pode aproveitar as funções head()
(ou first()
) para ver se o DataFrame
tem uma única linha. Nesse caso, não está vazio.
Se você fizer df.count > 0
. Ele pega a contagem de todas as partições em todos os executores e as adiciona no Driver. Isso demora um pouco quando você está lidando com milhões de linhas.
A melhor maneira de fazer isso é executar df.take(1)
e verificar se é nulo. Isso vai voltar, java.util.NoSuchElementException
então é melhor tentar df.take(1)
.
O dataframe retorna um erro quando take(1)
é concluído, em vez de uma linha vazia. Eu destaquei as linhas de código específicas onde ele lança o erro.
count
método levará algum tempo.
Desde Spark 2.4.0 existe Dataset.isEmpty
.
Sua implementação é:
def isEmpty: Boolean =
withAction("isEmpty", limit(1).groupBy().count().queryExecution) { plan =>
plan.executeCollect().head.getLong(0) == 0
}
Observe que a DataFrame
não é mais uma classe em Scala, é apenas um alias de tipo (provavelmente alterado com Spark 2.0):
type DataFrame = Dataset[Row]
Para usuários de Java, você pode usar isso em um conjunto de dados:
public boolean isDatasetEmpty(Dataset<Row> ds) {
boolean isEmpty;
try {
isEmpty = ((Row[]) ds.head(1)).length == 0;
} catch (Exception e) {
return true;
}
return isEmpty;
}
Isso verifica todos os cenários possíveis (vazio, nulo).
No Scala, você pode usar implícitos para adicionar os métodos isEmpty()
e nonEmpty()
à API DataFrame, o que tornará o código um pouco mais agradável de ler.
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
}
}
Aqui, outros métodos também podem ser adicionados. Para usar a conversão implícita, use import DataFrameExtensions._
no arquivo que deseja usar a funcionalidade estendida. Posteriormente, os métodos podem ser usados diretamente da seguinte forma:
val df: DataFrame = ...
if (df.isEmpty) {
// Do something
}
Eu tive a mesma pergunta e testei 3 soluções principais:
e claro os 3 trabalhos, porém em termos de desempenho, aqui está o que eu encontrei, ao executar esses métodos no mesmo DF da minha máquina, em termos de tempo de execução:
portanto, acho que a melhor solução é df.rdd.isEmpty como @Justin Pihony sugere
Descobri isso em alguns casos:
>>>print(type(df))
<class 'pyspark.sql.dataframe.DataFrame'>
>>>df.take(1).isEmpty
'list' object has no attribute 'isEmpty'
isso é o mesmo para "comprimento" ou substitua take () por head ()
[Solução] para o problema que podemos usar.
>>>df.limit(2).count() > 1
False
Se estiver usando o Pypsark, você também pode fazer:
len(df.head(1)) > 0
dataframe.limit(1).count > 0
Isso também aciona um trabalho, mas como estamos selecionando um único registro, mesmo no caso de bilhões de registros de escala, o consumo de tempo pode ser muito menor.
Você pode fazer assim:
val df = sqlContext.emptyDataFrame
if( df.eq(sqlContext.emptyDataFrame) )
println("empty df ")
else
println("normal df")
schema
de dois dataframes ( sqlContext.emptyDataFrame
& df
) seja o mesmo para retornar true
?
eq
é herdado de AnyRef
e testa se o argumento (that) é uma referência ao objeto receptor (this).