Como remover linhas duplicadas com PySpark no Databricks
Dados duplicados surgem por reprocessamentos, cargas repetidas ou junções mal desenhadas — e rapidamente inflacionam contagens, distorcem métricas e partem relatórios. Remover linhas duplicadas com PySpark no Databricks é uma das tarefas de limpeza mais comuns do dia a dia, e é simples quando se conhecem as funções certas. Este guia mostra, passo a passo, como identificar e eliminar duplicados, quer em todas as colunas quer apenas nas que definem um registo único. No final, guardas o resultado numa tabela Delta pronta a reutilizar.
Pré-requisitos
- Um workspace Databricks com um cluster (ou SQL warehouse) ativo.
- Um notebook Python anexado ao cluster.
- Noções básicas de Python e do conceito de DataFrame.
- A variável
sparkjá vem disponível em qualquer notebook Databricks.
Passo 1: Criar um DataFrame de exemplo com duplicados
Para acompanhar o exemplo, começamos por criar um pequeno DataFrame. Repara que a linha do id=2 está totalmente repetida e que o id=3 aparece duas vezes com cidades diferentes — ou seja, um duplicado apenas na coluna-chave. Estes dois casos exigem estratégias diferentes, como vais ver.
from pyspark.sql import Row
dados = [
Row(id=1, cliente="Ana", cidade="Porto", atualizado="2026-07-10"),
Row(id=2, cliente="Bruno", cidade="Lisboa", atualizado="2026-07-11"),
Row(id=2, cliente="Bruno", cidade="Lisboa", atualizado="2026-07-11"),
Row(id=3, cliente="Rita", cidade="Braga", atualizado="2026-07-12"),
Row(id=3, cliente="Rita", cidade="Faro", atualizado="2026-07-15"),
]
df = spark.createDataFrame(dados)
df.show()
Passo 2: Contar os duplicados antes de apagar
Antes de remover seja o que for, convém perceber quantos duplicados existem — assim confirmas o impacto da limpeza e detetas surpresas. Agrupar por todas as colunas e filtrar os grupos com mais de uma linha revela as repetições exatas. Guarda este número: no fim vais compará-lo com a contagem final para confirmar quantas linhas foram removidas.
print("Total de linhas:", df.count())
duplicados = (df.groupBy(df.columns)
.count()
.filter("count > 1"))
duplicados.show()
Passo 3: Remover linhas totalmente duplicadas
Quando duas linhas são iguais em todas as colunas, o método dropDuplicates() sem argumentos resolve o problema, mantendo apenas uma cópia de cada linha. O método distinct() faz exatamente o mesmo e é só uma forma mais curta de escrever. Ambos provocam um shuffle, por isso aplica-os depois de já teres filtrado colunas desnecessárias.
sem_duplicados = df.dropDuplicates()
print("Depois de dropDuplicates():", sem_duplicados.count())
# Equivalente:
sem_duplicados = df.distinct()
Passo 4: Remover duplicados por coluna-chave
Muitas vezes uma linha é considerada duplicada com base numa chave de negócio (por exemplo, o id), mesmo que as restantes colunas variem. Para esse caso, indica as colunas a considerar e o Spark deduplica só por elas.
por_chave = df.dropDuplicates(["id"])
por_chave.show()
Atenção: ao usar um subconjunto de colunas, o Spark mantém uma linha qualquer de cada grupo — não garante qual das linhas fica. Se isso for importante, usa o passo seguinte.
Passo 5: Manter o registo mais recente
Quando queres controlar qual a linha que sobrevive — por exemplo, ficar com a versão mais recente de cada id — usa uma janela (Window) com row_number(). A ideia é numerar as linhas dentro de cada grupo, ordenadas pela data descendente, e manter apenas a que recebe o número 1.
from pyspark.sql.window import Window
from pyspark.sql.functions import row_number, col
janela = Window.partitionBy("id").orderBy(col("atualizado").desc())
mais_recente = (df.withColumn("rn", row_number().over(janela))
.filter(col("rn") == 1)
.drop("rn"))
mais_recente.show()
Com esta abordagem, o id=3 fica com a cidade "Faro", por ser a atualização de 2026-07-15, e descartas a versão antiga de forma controlada.
Passo 6: Gravar o resultado numa tabela Delta
Para reutilizares os dados já limpos, guarda o DataFrame numa tabela Delta gerida. Ajusta o nome do catálogo e do schema ao teu ambiente.
(mais_recente.write
.format("delta")
.mode("overwrite")
.saveAsTable("vendas.clientes_limpos"))
Verificar o resultado
Compara a contagem antes e depois e confirma que já não existe nenhuma chave repetida. Se a última consulta não devolver linhas, a limpeza correu como esperado: passaste de 5 linhas para 3 registos únicos por id.
print("Linhas originais:", df.count())
print("Linhas finais:", mais_recente.count())
(mais_recente.groupBy("id")
.count()
.filter("count > 1")
.show())
Conclusão
Em poucos passos passaste de dados repetidos para um conjunto limpo e fiável: dropDuplicates() para linhas idênticas, um subconjunto de colunas para chaves de negócio e uma Window quando precisas de escolher exatamente qual registo manter. A partir daqui, podes agendar este notebook como um Job para correr automaticamente, ou combinar a lógica com MERGE INTO para deduplicar de forma incremental à medida que chegam novos dados. Qual será a coluna-chave que melhor identifica um registo único nos teus próprios dados?