Trilha de certificações
Databricks Certified Associate Developer for Apache Spark
Avalia a arquitetura do Apache Spark e o uso da DataFrame API em Python: manipular colunas e linhas, agregações, joins, leitura e escrita com schema, UDFs, Spark SQL, Structured Streaming, Spark Connect, Pandas API on Spark e tuning básico.
Formato da prova
- Questões
- 45 questões
- Duração
- 90 min
- Taxa
- US$ 200
- Idiomas
- Inglês
- Validade
- 2 anos
- Versão do guia oficial
- 08 de out. de 2026
Nenhum obrigatório. Recomenda-se seis meses de prática com Apache Spark.
O que cai e quanto pesa
- Arquitetura e componentes do Spark20%
- Spark SQL20%
- Aplicações com a DataFrame/Dataset API30%
- Troubleshooting e tuning10%
- Structured Streaming10%
- Spark Connect e modos de deploy5%
- Pandas API on Spark5%
Número aproximado de questões por seção, considerando as 45 questões pontuadas.
Seção 1 · 20% · ≈ 9 questões
Arquitetura e componentes do Spark
Objetivos oficiais
- Identificar vantagens e desafios de usar Spark.
- Identificar o papel dos componentes: cluster, driver, workers/executores, núcleos de CPU e memória.
- Descrever a arquitetura: DataFrame e Dataset, ciclo de vida da SparkSession, cache, storage levels e garbage collection.
- Explicar a hierarquia de execução.
- Configurar o particionamento: shuffles e partições.
- Descrever os padrões de execução: actions, transformations e lazy evaluation.
- Identificar os módulos: Core, Spark SQL, DataFrames, Pandas API on Spark, Structured Streaming e MLlib.
Quem faz o quê
- Driver: roda seu programa, cria o plano, divide em jobs/stages/tasks e agenda.
- Executores (nos workers): executam tasks e guardam dados em cache. Cada core executa uma task por vez.
- Cluster manager: entrega recursos (standalone, YARN, Kubernetes; na Databricks, gerenciado).
Hierarquia de execução
Application → Job (uma por action) → Stage (fronteira = shuffle) → Task (uma por partição).
Lazy evaluation
Transformations (select, filter, withColumn, join, groupBy) só constroem o plano. Actions (count, collect, show, take, write) disparam a execução. Isso deixa o Catalyst otimizar o plano inteiro (ex.: empurrar filtros para a leitura).
- Narrow (sem shuffle):
filter,select,map. - Wide (com shuffle):
groupBy,join,distinct,orderBy,repartition.
Partições
spark.sql.shuffle.partitions (padrão 200) define quantas partições saem de um shuffle. repartition(n) faz shuffle e pode aumentar/diminuir; coalesce(n) só diminui, sem shuffle completo.
Cache e storage levels
df.cache() = persist(StorageLevel.MEMORY_AND_DISK) para DataFrames (no PySpark recente aparece como MEMORY_AND_DISK_DESER, a variante desserializada). Outras: MEMORY_ONLY, DISK_ONLY, _SER, _2 (replicado). O cache também é lazy: só materializa na próxima action. unpersist() libera.
GC
Muito objeto na JVM → pausas de garbage collection (veja "GC time" na Spark UI). Ajuda: menos dados em cache, formatos serializados, partições menores, evitar UDFs Python que criam muitos objetos.
Vantagens e desafios
Processamento distribuído em memória, APIs unificadas (SQL, Python, streaming, ML), tolerância a falhas por linhagem. Desafios: tuning (memória, partições, skew), custo de shuffle, curva de aprendizado.
Pegadinhas comuns
- coalesce não aumenta o número de partições.
- cache() não executa nada sozinho.
Documentação:Visão geral do clusterRDD persistence / storage levels
Seção 2 · 20% · ≈ 9 questões
Spark SQL
Objetivos oficiais
- Usar fontes comuns (JDBC, arquivos) para ler e escrever DataFrames, incluindo sobrescrita e particionamento por coluna.
- Executar SQL direto sobre arquivos (ORC, JSON, CSV, texto, Delta) e entender os save modes.
- Salvar dados em tabelas persistentes aplicando ordenação e particionamento para otimizar a leitura.
- Registrar DataFrames como views temporárias e consultá-los com SQL.
Ler e escrever
df = (spark.read.format("csv").option("header", True).schema("id INT, pais STRING, valor DOUBLE")
.load("/data/vendas.csv"))
df.write.mode("overwrite").partitionBy("pais").parquet("/data/out")
jdbc = (spark.read.format("jdbc")
.option("url", "jdbc:postgresql://db:5432/erp").option("dbtable", "public.clientes")
.option("user", u).option("password", p).load())
Save modes
| Modo | Se o destino existe |
|---|---|
error / errorifexists (padrão) | Falha |
append | Acrescenta |
overwrite | Substitui |
ignore | Não faz nada |
SQL direto em arquivos
SELECT * FROM parquet.`/data/out`;
SELECT * FROM json.`/data/eventos/*.json`;
SELECT * FROM delta.`/data/tabela_delta`;
Tabelas persistentes
df.write.partitionBy("ano").sortBy("id").bucketBy(8, "id").saveAsTable("vendas") # sortBy exige bucketBy
saveAsTable registra no metastore/catálogo; continua existindo depois da sessão.
Views temporárias
df.createOrReplaceTempView("vendas_v") # só nesta SparkSession
df.createOrReplaceGlobalTempView("vendas_g") # global_temp.vendas_g, todas as sessões da aplicação
spark.sql("SELECT pais, SUM(valor) FROM vendas_v GROUP BY pais").show()
Pegadinhas comuns
- O save mode padrão é errorifexists, não overwrite.
- Global temp view fica no schema global_temp.
Documentação:Data sourcesSave modes
Seção 3 · 30% · ≈ 14 questões
Aplicações com a DataFrame/Dataset API
Objetivos oficiais
- Manipular colunas, linhas e estrutura: adicionar, remover, dividir e renomear colunas, filtrar e explodir arrays.
- Deduplicar e validar DataFrames.
- Agregar: count, contagem distinta aproximada, média e summary.
- Manipular datas: epoch Unix para string de data e extrair componentes.
- Combinar DataFrames com inner, left, broadcast, múltiplas chaves, cross join, union e union all.
- Ler, escrever e sobrescrever DataFrames com schema.
- Ordenar, iterar, imprimir o schema e converter DataFrame em lista.
- Criar e invocar UDFs com ou sem operadores com estado (StateStore).
- Descrever variáveis broadcast e acumuladores.
- Descrever o propósito e a implementação de broadcast joins.
Colunas
from pyspark.sql import functions as F
df = (df.withColumn("state", F.col("division")).drop("division")
.withColumnRenamed("mName", "managerName")
.withColumn("partes", F.split("endereco", ","))
.withColumn("tag", F.explode("tags"))
.filter((F.col("valor") > 0) & F.col("pais").isin("BR", "PT")))
Nulos e duplicatas
df.na.drop() (= how="any": remove linha com qualquer nulo); na.drop("all") só se todas forem nulas; subset=[...]; na.fill({"col": 0}); dropDuplicates(["id"]); distinct().
Agregações
df.groupBy("pais").agg(F.count("*").alias("n"), F.avg("valor"), F.approx_count_distinct("usuario"))
df.summary().show() # count, mean, stddev, min, 25%, 50%, 75%, max
approx_count_distinct usa HyperLogLog: muito mais barato que countDistinct, com erro pequeno configurável.
Datas
df.withColumn("data", F.from_unixtime("epoch", "yyyy-MM-dd")) \
.withColumn("ts", F.to_timestamp(F.from_unixtime("epoch"))) \
.withColumn("ano", F.year("ts")).withColumn("mes", F.month("ts")).withColumn("dia_semana", F.dayofweek("ts"))
Joins e unions
a.join(b, ["id", "data"], "left"), a.crossJoin(b), a.join(F.broadcast(b), "id"). union (= UNION ALL, por posição), unionByName (por nome; allowMissingColumns=True).
Ordenar, schema, listas
linhas = df.orderBy(F.col("salary").desc(), F.col("age").desc()).collect() # lista de Row
df.printSchema()
lista = [r.asDict() for r in linhas]
for r in df.toLocalIterator(): ... # itera sem trazer tudo de uma vez
UDFs
@F.udf("string")
def normaliza(s): return s.strip().lower() if s else None
df.withColumn("nome_n", normaliza("nome"))
spark.udf.register("normaliza", normaliza) # usar em SQL
Prefira funções nativas (mais rápidas). UDF sem estado aplica lógica por linha; lógica com estado entre eventos (sessões, totais acumulados) usa operadores com estado de streaming (applyInPandasWithState, transformWithState) que guardam dados no StateStore.
Broadcast e acumuladores
- Broadcast variable: valor somente leitura enviado uma vez por executor (ex.: dicionário de lookup).
- Accumulator: contador que os executores só somam e o driver lê (ex.: contar registros inválidos).
- Broadcast join: a tabela pequena vai inteira para cada executor → a grande não precisa de shuffle. Automático abaixo de
spark.sql.autoBroadcastJoinThreshold(10 MB) ou comF.broadcast().
Pegadinhas comuns
- df.na.drop() sem argumentos já é how='any'.
- union junta por posição; colunas em ordem diferente geram dados trocados sem erro.
- collect() traz tudo para o driver — cuidado com OOM.
Documentação:PySpark APIFunções SQL
Seção 4 · 10% · ≈ 5 questões
Troubleshooting e tuning
Objetivos oficiais
- Aplicar estratégias de desempenho e uso do cluster: particionar, reparticionar, coalescer, identificar skew e reduzir shuffle.
- Descrever o Adaptive Query Execution (AQE) e seus benefícios.
- Fazer logging e monitoramento: publicar, customizar e analisar logs de driver e executores para diagnosticar OOM, subutilização etc.
Estratégias
- Poucas partições → cores ociosos; muitas → overhead. Regra prática: partições de ~100–200 MB, pelo menos 2–3× o número de cores.
- Skew: uma chave com muito mais dados → uma task lenta. Veja Max ≫ Median na Spark UI. Soluções: AQE skew join, salting, broadcast.
- Menos shuffle: filtre e selecione cedo, broadcast de tabelas pequenas, evite
distinct/orderBydesnecessários.
AQE (ligado por padrão desde o Spark 3.2)
Reotimiza o plano em tempo de execução com estatísticas reais:
- Coalesce de partições pós-shuffle (junta partições pequenas);
- Troca de estratégia de join (sort-merge → broadcast quando um lado ficou pequeno);
- Skew join (divide partições gigantes).
Logs
Logs de executor e driver pela Spark UI (aba Executors → stdout/stderr) ou pelos logs do cluster. spark.sparkContext.setLogLevel("WARN") ajusta o nível; use log4j2 para customizar. Sinais: OutOfMemoryError no driver (collect grande), executor lost/OOM (partições grandes, skew), CPU ociosa (poucas partições).
Documentação:AQEMonitoramento
Seção 5 · 10% · ≈ 5 questões
Structured Streaming
Objetivos oficiais
- Explicar o engine: modelo de programação, micro-batches, semântica exactly-once e tolerância a falhas.
- Criar e gravar Streaming DataFrames/Datasets com os output modes e sinks básicos.
- Fazer operações básicas: seleção, projeção, janela e agregação.
- Fazer deduplicação em streaming com e sem watermark.
Modelo
O stream é uma tabela sem fim; sua query roda incrementalmente em micro-batches. Checkpoint (offsets + estado) + fonte reprocessável + sink idempotente = exactly-once.
eventos = (spark.readStream.format("json").schema(schema).load("/data/in"))
contagem = (eventos.withWatermark("ts", "10 minutes")
.groupBy(F.window("ts", "15 minutes", "5 minutes"), "produto").count())
(contagem.writeStream.outputMode("update").format("console")
.option("checkpointLocation", "/chk/contagem").trigger(processingTime="2 minutes").start())
Output modes
append (só linhas novas/finais), update (linhas que mudaram), complete (resultado inteiro — só com agregação).
Sinks
File (parquet, json…), Kafka, foreach / foreachBatch, console e memory (debug), tabelas (toTable).
Deduplicação
eventos.dropDuplicates(["evento_id"]) # estado cresce para sempre
eventos.withWatermark("ts", "1 hour").dropDuplicates(["evento_id", "ts"]) # estado limitado pela watermark
eventos.withWatermark("ts", "1 hour").dropDuplicatesWithinWatermark(["evento_id"])
Documentação:Structured Streaming
Seção 6 · 5% · ≈ 2 questões
Spark Connect e modos de deploy
Objetivos oficiais
- Descrever os recursos do Spark Connect.
- Descrever os modos de deploy (client, cluster e local).
Spark Connect
Arquitetura cliente-servidor: o cliente leve (Python, Scala, Go…) envia planos lógicos via gRPC para o servidor Spark remoto. Vantagens: rodar Spark a partir de IDEs, notebooks e apps sem JVM local; isolamento (um cliente que trava não derruba o driver); upgrades independentes. SparkSession.builder.remote("sc://host:15002").getOrCreate(). Na Databricks, é a base do Databricks Connect e do serverless.
Modos de deploy
| Modo | Onde fica o driver |
|---|---|
| Client | Na máquina que submeteu (bom para interativo) |
| Cluster | Dentro do cluster (bom para produção; independe da máquina do usuário) |
| Local | Tudo em uma JVM numa máquina; executores são threads (local[*]) — testes e desenvolvimento |
Documentação:Spark Connect
Seção 7 · 5% · ≈ 2 questões
Pandas API on Spark
Objetivos oficiais
- Explicar as vantagens da Pandas API on Spark.
- Criar e invocar Pandas UDFs.
Pandas API on Spark
import pyspark.pandas as ps
psdf = ps.read_csv("/data/vendas.csv")
psdf.groupby("pais")["valor"].mean().sort_values()
psdf.to_spark() # volta a ser DataFrame do Spark; df.pandas_api() faz o caminho inverso
Sintaxe do pandas com execução distribuída — migração de código pandas para dados que não cabem numa máquina.
Pandas UDF
import pandas as pd
from pyspark.sql.functions import pandas_udf
@pandas_udf("double")
def com_imposto(valor: pd.Series) -> pd.Series:
return valor * 1.1
df.withColumn("valor_final", com_imposto("valor"))
Vetorizada com Apache Arrow: processa lotes inteiros, muito mais rápida que UDF Python linha a linha.
Documentação:Pandas API on Spark
Treinamentos recomendados pela Databricks
- Instrutor: Apache Spark Programming with Databricks
- Academy: Introduction to Apache Spark
- Academy: Developing Applications with Apache Spark
- Academy: Stream Processing and Analysis with Apache Spark
- Academy: Monitoring and Optimizing Apache Spark Workloads on Databricks