Snowpark Migration Accelerator: conversão de notebooks¶
Vamos acessar o Notebook de relatórios em nossa base de código: Notebook de relatórios básicos – SqlServer Spark.ipynb. Vamos percorrer um conjunto de etapas semelhante ao que fizemos com o script do pipeline.
Resolver todos os problemas: «problemas» aqui significa os problemas gerados pelo SMA. Analise o código de saída. Resolva os erros de análise e conversão e investigue os avisos.
Resolver as chamadas de sessão: a forma como a chamada de sessão é escrita no código de saída depende de onde vamos executar o arquivo. Vamos resolver isso para executar os arquivos de código na mesma localização em que seriam executados originalmente e, em seguida, para executá-los no Snowflake.
Resolver as entradas/saídas: não é possível resolver as conexões com diferentes fontes completamente pelo SMA. Existem diferenças entre as plataformas, e o SMA geralmente ignora isso. Isso também é afetado por onde o arquivo será executado.
Limpar e testar: vamos executar o código. Veja se funciona. Neste laboratório, faremos testes básicos, mas existem ferramentas para realizar testes e validações de dados mais extensivos, incluindo o Snowpark Python Checkpoints.
Vamos começar.
Resolver todos os problemas¶
Vamos analisar os problemas presentes no notebook.
(Observe que você pode abrir o notebook no VS Code, mas para visualizá-lo corretamente, talvez queira instalar a extensão Jupyter para VS Code. Como alternativa, você pode abri-lo no Jupyter, mas a Snowflake ainda recomenda o VS Code com a extensão Snowflake instalada).
Você pode usar o recurso de comparação para visualizar ambos lado a lado, como fizemos com o arquivo de pipeline, embora ele se pareça mais com um JSON se você fizer isso:

Observe que existem apenas dois EWIs exclusivos neste notebook. Você pode retornar à barra de pesquisa para encontrá-los, mas como este é muito curto, também é possível simplesmente… rolar para baixo. Estes são os problemas exclusivos:
SPRKPY1002 => pyspark.sql.readwriter.DataFrameReader.jdbc não é compatível. Esse problema é semelhante ao que vimos no arquivo de pipeline, mas aquele era uma chamada de gravação. Esta é uma chamada de leitura para o banco de dados do SQL Server. Vamos resolver isso em breve.
SPRKPY1068 => «pyspark.sql.dataframe.DataFrame.toPandas não é compatível se há colunas do tipo ArrayType, mas existe uma solução alternativa. Consulte a documentação para obter mais informações. Este é outro aviso. Se passarmos uma matriz para esta função no Snowpark, ela pode não funcionar. Vamos ficar de olho nisso quando testarmos.
E é isso para o notebook… e nossos problemas. Resolvemos um erro de análise sintática, reconhecemos que teremos que corrigir as entradas/saídas e há algumas diferenças funcionais em potencial que devemos observar. Vamos para a próxima etapa: resolução das chamadas de sessão.
Resolver as chamadas de sessão¶
Para atualizar as chamadas de sessão no notebook de relatório, precisamos localizar a célula com a chamada de sessão. Fica assim:

Agora vamos fazer o que já fizemos para o nosso arquivo de pipeline:
Altere todas as referências à variável de sessão «spark» para «session» (observe que isso ocorre em todo o notebook).
Remova a função de configuração com o driver spark.
O antes e o depois ficarão assim:
# Old Session
spark = Session.builder.config('spark.driver.extraClassPath', driver_path).app_name("AdventureWorksSummary", True).getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":7,"minor":4,"patch":10},"attributes":{"language":"Python"}})
# New Session
# Session
session = Session.builder.app_name("AdventureWorksSummary", True).getOrCreate()
session.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":7,"minor":4,"patch":10},"attributes":{"language":"Python"}})
Observe que há outro código nesta célula. Esse código:
url = sql_server_url
properties = {'user' : sql_server_user, 'password' : sql_server_password}
# Spark dataframe.
#EWI: SPRKPY1002 => pyspark.sql.readwriter.DataFrameReader.jdbc is not supported
df = session.read.jdbc(url = url, table = 'dbo.DimCustomer', properties = properties)
print('Session successfully setup.')
Estamos quase prontos para lidar com a instrução de leitura, mas ainda não chegamos lá. Vamos mover tudo isso para outra célula. Crie uma nova célula abaixo desta e mova este código para ela. Ficará assim:

Isso é tudo o que precisamos para a chamada de sessão? Não. Relembre (e possivelmente releia) a página anterior em Notas sobre chamadas de sessão. Você precisará certificar-se de que seu arquivo connection.toml tem suas informações de conexão ou precisará especificar explicitamente os parâmetros de conexão que pretende usar na sessão.
Resolução das entradas/saídas¶
Vamos resolver nossas entradas e saídas agora. Observe que isso pode variar dependendo se você está executando os arquivos localmente ou no Snowflake; mas, para o notebook, tudo pode ser executado localmente ou no Snowflake. O código será um pouco mais simples, pois nem precisaremos chamar uma sessão. Vamos apenas… obter a sessão ativa. Assim como no arquivo de pipeline, faremos isso em duas partes: uma para ser executada/orquestrada localmente e outra para ser executada no Snowflake.
Trabalhar com as entradas e saídas no notebook de relatório será consideravelmente mais simples do que foi para o pipeline. Não há leitura de um arquivo local nem movimentação de dados entre arquivos. Há simplesmente uma leitura de uma tabela no SQL Server que agora é uma leitura de uma tabela no Snowflake. Como não acessaremos o SQL Server, podemos descartar qualquer referência às propriedades do SQL Server. E é possível substituir a instrução de leitura por uma instrução de tabela no Snowflake. O antes e o depois desta célula devem ser assim:
# Before
url = sql_server_url
properties = {'user' : sql_server_user, 'password' : sql_server_password}
# Spark dataframe.
#EWI: SPRKPY1002 => pyspark.sql.readwriter.DataFrameReader.jdbc is not supported
df = session.read.jdbc(url = url, table = 'dbo.DimCustomer', properties = properties)
print('Session successfully setup.')
# After
# New table call
# Snowpark Dataframe table.
df = session.table('ADVENTUREWORKS.DBO.DIMCUSTOMER')
print('Table loaded successfully.')
df.show()

Na verdade, é isso. Vamos passar para a parte de limpeza e teste do arquivo notebook.
Limpar e testar¶
Vamos fazer uma limpeza (como fizemos antes para o arquivo de pipeline). Nunca analisamos nossas chamadas de importação e temos arquivos de configuração que não são necessários. Vamos começar removendo as referências aos arquivos de configuração. Isso será em cada uma das células entre as instruções de importação e a chamada de sessão.

Agora vamos analisar nossas importações. A referência ao SO pode ser excluída (parece que isso também não era utilizado no arquivo original). Há uma referência ao pandas. Não parece haver mais nenhum uso do pandas neste notebook agora que os arquivos de configuração são referenciados. Há uma referência toPandas como parte da API do dataframe Snowpark na seção de relatórios, mas isso não faz parte da biblioteca pandas.
Como opção, você pode substituir todas as chamadas de importação para pandas pela biblioteca modin pandas. Essa biblioteca otimizará os dataframes pandas para aproveitar o grande poder computacional do Snowflake. Essa alteração ficaria assim:
# Old
import pandas as pd
# New
import modin.pandas as pd
import snowflake.snowpark.modin.plugin
Dito isso, podemos excluir este também. Observe que o SMA substituiu todas as instruções de importação específicas do Spark por aquelas relacionadas ao Snowpark. A célula de importação final ficaria assim:

E é isso para a nossa limpeza. Ainda temos alguns EWIs nas células de relatório e exibição, mas parece que vamos conseguir. Vamos executar este e ver se conseguimos uma saída.

E conseguimos. Os relatórios parecem corresponder ao que foi gerado pelo Spark Notebook. Embora as células de relatório parecessem complexas, o Snowpark consegue trabalhar com elas. O SMA indicaria se pudesse haver um problema, mas aparentemente não há nenhum. Mais testes seriam úteis, mas nossa primeira rodada de testes rápidos foi concluída com sucesso.
Agora, vamos analisar este notebook no Snowsight. Ao contrário do arquivo de pipeline, podemos fazer tudo isso no Snowsight.
Execução do notebook no Snowsight¶
Vamos pegar a versão do notebook que temos agora (após termos trabalhado nos problemas, nas chamadas de sessão e nas entradas e saídas) e carregá-la no Snowflake. Para isso, acesse a seção de notebooks em SnowSight:

Selecione a seta para baixo ao lado do botão +Notebook no canto superior direito e depois “Import .ipynb file” (mostrado acima).
Após a importação, escolha o arquivo de notebook com o qual estávamos trabalhando no diretório de saída criado pelo SMA na pasta do seu projeto.
Uma janela de diálogo para criar notebook será aberta. Para este upload, escolheremos as seguintes opções:
Localização do notebook:
Banco de dados: ADVENTUREWORKS
Esquema: DBO
Ambiente Python: executar no warehouse
Este não é um notebook grande com muito ML. É um notebook básico de relatórios. Podemos executá-lo em um warehouse.
Warehouse de consultas: DEFAULT_WH
Warehouse de notebooks: DEFAULT_WH (você pode deixar como o repositório escolhido pelo sistema – será um repositório Streamlit – para este notebook, não fará diferença)
Você pode ver essas seleções abaixo:

Isso deve carregar seu notebook no Snowflake, e ele ficará com esta aparência:

Há algumas verificações/alterações rápidas que precisamos fazer em relação à versão que acabamos de testar localmente para garantir que o notebook seja executado no Snowsight:
Alterar as chamadas de sessão para recuperar a sessão ativa
Garantir que todas as bibliotecas dependentes que precisamos instalar estejam disponíveis
Vamos começar com a primeira. Pode parecer estranho alterar a chamada de sessão novamente depois de termos investido tanto tempo nisso inicialmente, mas agora estamos executando dentro do Snowflake. Você pode remover tudo o que estiver associado à leitura da chamada de sessão e substituir pela chamada “get_active_session”, que é padrão no início da maioria dos notebooks do Snowflake:
//# Old for Jupyter
session = Session.builder.app_name("AdventureWorksSummary", True).getOrCreate()
# New for Snowsight
from snowflake.snowpark.context import get_active_session
session = get_active_session()
Não precisamos especificar parâmetros de conexão nem atualizar um arquivo .toml, porque já estamos conectados. Estamos no Snowflake.
Vamos substituir o código antigo na célula pelo código novo. O resultado será algo com esta aparência:

Agora, vamos verificar os pacotes disponíveis para esta execução, mas sem a necessidade de descobrirmos o que precisamos adicionar. Vamos deixar o Snowflake. Uma das melhores vantagens de usar um notebook é poder executar células individuais e ver os resultados. Vamos executar nossa célula de biblioteca de importação.
Se você ainda não fez isso, inicie a sessão clicando no canto superior direito da tela, onde está escrito «Start»:

Se você executar a célula superior do notebook, provavelmente descobrirá que o matplotlib não está carregado na sessão:

Isto é algo muito importante para este notebook. Você pode adicionar essa biblioteca ao seu notebook/sessão usando a opção “Packages” no canto superior direito do notebook:

Procure por matplotlib e selecione-o. Isso disponibilizará este pacote na sessão.

Depois de carregar esta biblioteca, você precisará reiniciar a sessão. Após reiniciar a sessão, execute a primeira célula novamente. Você provavelmente verá uma mensagem informando que a operação foi bem-sucedida desta vez.

Com os pacotes carregados, a sessão corrigida e os demais problemas no código já resolvidos, o que podemos fazer para verificar o restante do notebook? Executá-lo! Você pode executar todas as células do notebook selecionando “Run all” no canto superior direito da tela e verificar se ocorre algum erro.
Parece que a execução foi bem-sucedida:

Se você comparar a execução dos dois notebooks, parece que a única diferença é que a versão do Snowflake colocou todos os conjuntos de dados de saída primeiro, seguidos pelas imagens, enquanto no Spark Jupyter Notebook eles estão misturados:

Observe que essa diferença não é uma diferença na API, mas sim em como os notebooks no Snowflake orquestram isso. Essa é provavelmente uma diferença que o AdventureWorks está disposto a aceitar!
Conclusões¶
Ao utilizar o SMA, conseguimos acelerar a migração tanto de um pipeline de dados quanto de um notebook de relatórios. Quanto mais de cada um você tiver, mais valor uma ferramenta como o SMA poderá fornecer.
Vamos voltar ao fluxo de avaliação -> conversão -> validação ao qual sempre retornamos. Nesta migração, nós:
Configuramos nosso projeto no SMA
Executamos o mecanismo de avaliação e conversão do SMA nos arquivos de código
Revisamos os relatórios de saída do SMA para entender melhor o que temos
Revisamos o que não pôde ser convertido pelo SMA no VS Code
Resolvemos problemas e erros
Resolvemos referências de sessão
Resolvemos referências de entrada/saída
Executamos o código localmente
Executamos o código no Snowflake
Executamos os scripts recém-migrados e validamos o sucesso deles
A Snowflake investiu muito tempo aprimorando os recursos de ingestão e de engenharia de dados, assim como passou tempo aprimorando ferramentas de migração como o SnowConvert, o assistente de migração do SnowConvert e o Snowpark Migration Accelerator. Cada uma dessas ferramentas continuará a ser aprimorada. Entre em contato caso tenha alguma sugestão para as ferramentas de migração. Essas equipes estão sempre em busca de mais feedback para aprimorar as ferramentas.