O conceito fundamental do Spark que todo iniciante precisa dominar
Aprofundamento CEVIU
Aprofundamento
O modelo lazy evaluation do Spark não é só uma curiosidade de implementação: ele permite otimizações cruciais no nível do Catalyst Optimizer e do Tungsten Execution Engine. Quando você chama filter(), select() ou join(), o Spark não executa nada, apenas enriquece o plano lógico do DAG com operadores que serão posteriormente transformados em um plano físico otimizado, com fusão de estágios, eliminação de colunas desnecessárias e pushdown de filtros para fontes externas (como Parquet ou Iceberg). Isso explica por que o mesmo pipeline rodando em Spark + Iceberg pode ter latência 3x menor que em Spark + Hive: o Catalyst entende os metadados do Iceberg e evita leituras completas de partições.
O conceito também se conecta diretamente ao uso real de Arrow no ecossistema: como o Spark 3.5+ passou a usar Arrow como formato interno entre etapas de execução (não só em integrações com Pandas), as transformações lazy ganham eficiência extra, menos cópias de memória, zero serialização entre executors, e melhor aproveitamento de vetores SIMD. Isso não aparece nos tutoriais básicos, mas é o que separa pipelines que escalam linearmente de outros que travam com 10 TB de dados.
O que mudou
A cobertura anterior do CEVIU sobre Spark era implícita e fragmentada, aparecia em contextos como Kafka/Structured Streaming (2026-05-30) e na migração da Netflix para Iceberg (2026-05-21), mas sempre como pressuposto técnico, nunca como objeto central. Agora, pela primeira vez, o CEVIU trata a distinção entre transformações e ações como um conceito fundador, não como detalhe de API, mas como chave de leitura para arquiteturas reais: por exemplo, por que um count() mal posicionado pode derrubar um job de streaming, ou por que o Liquid Clustering (2026-06-04) só entrega vantagem quando combinado com planos lógicos bem estruturados pelo Catalyst.
Por que isso importa
Quem confunde transformação com execução acaba escrevendo pipelines com múltiplos cache() desnecessários, triggers de checkpoint mal sincronizados em streaming, ou até submetendo jobs que nunca rodam, porque esqueceu a ação final. Em ambientes corporativos, isso se traduz em custos ocultos com recursos subutilizados, SLAs quebrados por causa de shuffles não previstos, e dificuldade para depurar falhas no DAG. Dominar essa distinção permite ler o Spark UI com precisão: cada estágio visível ali corresponde a um ponto onde uma ação forçou a materialização de parte do grafo, e não a cada linha de código escrita.
Linha do tempo
Netflix migra movimentação de dados do Cassandra para Iceberg usando Spark DataFrames
Análise de falhas em arquiteturas Kafka + Spark Structured Streaming em produção
Databricks demonstra como Liquid Clustering depende de planos lógicos otimizados pelo Catalyst
Publicação que estabelece a distinção entre transformações e ações como conceito fundador do Spark
Perguntas frequentes
Se transformações são lazy, por que meu DataFrame parece 'pronto' logo após um select()?
Ele está pronto apenas como plano lógico, não há dados carregados, nem leitura feita. O Spark só acessa a fonte (S3, JDBC, etc.) quando uma ação como show(), count() ou write() é chamada. Você pode até chamar 100 transformações seguidas sem consumir um único byte de rede.
O que acontece se eu chamar cache() em uma transformação lazy?
Nada imediatamente. O cache só é preenchido na primeira ação subsequente que force a computação dessa ramificação do DAG. Se o DataFrame nunca for usado depois disso, o cache fica vazio e ocupa memória à toa.
Como saber se meu job está fazendo shuffle desnecessário?
Verifique o Spark UI: estágios com grandes volumes em 'Shuffle Read/Write' geralmente vêm de ações como repartition(), join() ou groupBy() sem otimizações prévias. Um filter() antes do join() pode reduzir o shuffle em 90%, mas só se for parte do mesmo DAG, não se você já tiver chamado uma ação intermediária.
Isso vale para Structured Streaming também?
Sim, e com mais impacto. Cada microbatch constrói um DAG independente. Se você usar uma transformação lazy dentro de um foreachBatch sem uma ação explícita (como df.write...), o processamento simplesmente não ocorre, e nenhum erro é lançado. É um dos erros mais comuns em produção, detectado só por métricas faltantes.
- Categoria
- CEVIU Dados
- Publicado
- 08 de junho de 2026
- Fonte
- CEVIU Dados
