Poucos discordariam que a palavra "preguiçoso" tem uma conotação negativa. Geralmente descrevemos alguém que não está disposto a trabalhar duro como preguiçoso. No entanto, nem toda preguiça é indesejável, e às vezes preferimos preguiça à diligência, especialmente no mundo da ciência da computação. Um exemplo é a avaliação preguiçosa. Hoje, vamos inspecionar de perto por que a avaliação preguiçosa é essencial para o alto desempenho do Spark e como a avaliação preguiçosa funciona no Spark.
Vamos começar pela definição de avaliação preguiçosa. Segundo a Wikipédia, avaliação preguiçosa é uma estratégia de avaliação que atrasa a avaliação de uma expressão até que seu valor seja necessário. Em outras palavras, se uma expressão for avaliada de forma preguiçosa, seu valor não será calculado até que seja necessário. Você pode perguntar: por que não podemos avaliar a expressão assim que a encontramos, ou seja, avaliá-la com avidadez? As razões são duas:
Primeiramente, a avaliação preguiçosa ajuda a melhorar a eficiência do Spark. O Spark usa um otimizador de catalisadores para buscar automaticamente a forma mais eficiente de executar operações de dados. Se avaliássemos com entusiasmo todas as expressões no Spark, o otimizador catalisador otimizaria separadamente os planos de execução para o cálculo de todas as expressões intermediárias. Assim, o otimizador catalisador não poderia produzir um plano de execução globalmente ótimo. Pelo contrário, se adotarmos a estratégia de avaliação preguiçosa e pularmos o cálculo de todas as expressões intermediárias, então o otimizador catalisador pode analisar toda a cadeia de operações, obtendo assim as informações necessárias para gerar um plano de execução globalmente ótimo.
Um exemplo simples seria adicionar uma nova coluna a um DataFrame e removê-la. Se avaliarmos preguiçosamente a expressão final, então o otimizador catalisador pode analisar a cadeia geral de operações. Como a adição e remoção de uma nova coluna equivalem a nenhuma operação, o otimizador catalisador instruirá o Spark a não alterar o DataFrame inicial ao extrair seus dados, tornando todo o processo altamente eficiente. No entanto, se avaliássemos com entusiasmo todas as expressões, incluindo as intermediárias, o otimizador catalisador não teria informações suficientes para eliminar as operações de adição e remoção, resultando em ineficiência geral.

Segundo, a avaliação preguiçosa reduz o espaço total necessário para armazenar os dados. Se o Spark avaliasse avidamente todas as expressões intermediárias, então essas expressões precisavam ocupar algum espaço. Em contraste, a avaliação preguiçosa ajuda a reduzir o armazenamento temporário usado para armazenar expressões intermediárias. Como resultado, a avaliação preguiçosa também melhora a utilização geral do espaço do Spark.
Agora que estabelecemos que a avaliação preguiçosa é crucial para o esforço do Spark de melhorar a eficiência geral, vamos analisar como funciona a avaliação preguiçosa no Spark. Em vez de avaliar avidamente todas as expressões e calcular os dados correspondentes a cada expressão, o Spark usa DataFrames para representar os dados. Esses DataFrames são essencialmente DAGs (Gráficos Acíclicos Direcionados), contendo informações sobre todas as fontes de dados e modificações necessárias para gerar os dados descritos por esses DataFrames. Como podemos ver, os DataFrames são essenciais para a concretização da avaliação preguiçosa no Spark.

Para alterar os dados representados por um DataFrame, podemos aplicar transformações a ele. Transformações especificam como modificar um DataFrame sem realizar as modificações reais. O Spark não executa as modificações até chamar uma ação em um DataFrame. Ao contrário das transformações, as ações são avaliadas com entusiasmo. Elas envolvem extrair os dados reais representados pelo DataFrame. (Você pode ler mais sobre transformações e ações neste blog.)
Vamos dar uma olhada em outro exemplo. Como mostrado no fluxograma abaixo, começamos com um DataFrame contendo três colunas: usuário_id, usuário_name e locatário_id. Nossa primeira transformação é adicionar a coluna mascarada_user_name ao DataFrame. Após a transformação, terminamos com um DataFrame contendo quatro colunas: usuário_id, usuário_name, mascarado_user_name e tenant_id. Depois, realizamos outra transformação para remover a coluna usuário_name, resultando em um DataFrame contendo três colunas: usuário_id, mascarado_user_name e inquilino_id. Por fim, juntamos o DataFrame a outro DataFrame contendo duas colunas: inquilino_id e locatário_name. Pode parecer que fizemos muitos cálculos até aqui. No entanto, a verdade é que apenas realizamos transformações de DataFrame sem envolver qualquer avaliação, já que os DataFrames são avaliados de forma preguiçosa. A avaliação só começa depois que o método all() é chamado no DataFrame final, que é a única ação em todo o processo.

Resumindo, a avaliação preguiçosa facilita o esforço do Spark para otimizar o desempenho de tempo e espaço, e a Spark depende de DataFrames e Transformações para alcançar uma avaliação preguiçosa. Espero que este artigo ajude a melhorar sua compreensão sobre o Spark e a avaliação preguiçosa.
Leituras adicionais: Catalyst Optimizer: O Poder do Spark SQL Mergulhe profundamente no Catalyst Optimizer do Spark SQL Ações de Grafos Acíclicos Dirigidos, Transformações Estreitas e Transformações Amplas