Snowpark Migration Accelerator: Códigos de problema para Python

SPRKPY1089

Mensagem: Os valores de pyspark.sql.readwriter.DataFrameWriter.options no Snowpark podem ser diferentes, portanto, pode ser necessária uma validação.

Categoria: Aviso

Descrição

Os valores de pyspark.sql.readwriter.DataFrameWriter.options no Snowpark podem ser diferentes, portanto, pode ser necessária uma validação para garantir que o comportamento esteja correto.

Cenários

Há alguns cenários, dependendo do fato de as opções terem suporte ou não, ou do formato usado para gravar o arquivo.

Cenário 1

Entrada

Veja a seguir um exemplo de uso das opções de método, adicionando as opções sep e nullValue, que atualmente são suportadas.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])

df.write.options(nullValue="myVal", sep=",").csv("some_path")
Copy

Saída

A ferramenta adiciona EWI SPRKPY1089 indicando que se trata de uma validação obrigatória.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])
#EWI: SPRKPY1089 => The pyspark.sql.readwriter.DataFrameWriter.options values in Snowpark may be different, so required validation might be needed.
df.write.options(nullValue="myVal", sep=",").csv("some_path")
Copy

Correção recomendada

O Snowpark API é compatível com esses parâmetros, portanto, a única ação a ser tomada é verificar o comportamento após a migração. Consulte a tabela Equivalências para ver os parâmetros compatíveis.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])
#EWI: SPRKPY1089 => The pyspark.sql.readwriter.DataFrameWriter.options values in Snowpark may be different, so required validation might be needed.
df.write.options(nullValue="myVal", sep=",").csv("some_path")
Copy
Cenário 2

Entrada

Aqui o cenário mostra o uso de opções, mas adiciona uma opção de cabeçalho, que não é suportada.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])

df.write.options(header=True, sep=",").csv("some_path")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1089 indicando que a validação é necessária.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])
#EWI: SPRKPY1089 => The pyspark.sql.readwriter.DataFrameWriter.options values in Snowpark may be different, so required validation might be needed.
df.write.options(header=True, sep=",").csv("some_path")
Copy

Correção recomendada

Para esse cenário, é recomendável avaliar as opções de tipo de formato do Snowpark para ver se é possível alterá-lo de acordo com suas necessidades. Além disso, verifique o comportamento após a alteração.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])
#EWI: SPRKPY1089 => The pyspark.sql.readwriter.DataFrameWriter.options values in Snowpark may be different, so required validation might be needed.
df.write.csv("some_path")
Copy
Cenário 3

Entrada

Esse cenário adiciona uma opção sep, que é suportada e usa o método JSON.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])

df.write.options(nullValue="myVal", sep=",").json("some_path")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1089 indicando que a validação é necessária.

  • Observação: esse cenário também se aplica a PARQUET.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])
#EWI: SPRKPY1089 => The pyspark.sql.readwriter.DataFrameWriter.options values in Snowpark may be different, so required validation might be needed.
df.write.options(nullValue="myVal", sep=",").json("some_path")
Copy

Correção recomendada

O formato de arquivo JSON não é compatível com o parâmetro sep, portanto, é recomendável avaliar as opções de tipo de formato do Snowpark para ver se é possível alterá-lo de acordo com suas necessidades. Além disso, verifique o comportamento após a alteração.

df = spark.createDataFrame([(1, "myVal")], [2, "myVal2"], [None, "myVal3" ])
#EWI: SPRKPY1089 => The pyspark.sql.readwriter.DataFrameWriter.options values in Snowpark may be different, so required validation might be needed.
df.write.json("some_path")
Copy

Recomendações adicionais

  • Como existem alguns parâmetros não suportados, recomenda-se verificar a tabela de equivalências e verificar o comportamento após a transformação.

  • Tabela de equivalências:

O Snowpark pode oferecer suporte a uma lista de equivalências para alguns parâmetros:

Opção PySpark

Opção SnowFlake

Formatos de arquivo suportados

Descrição

SEP

FIELD_DELIMITER

CSV

Um ou mais caracteres de byte único ou de vários bytes que separam os campos em um arquivo de entrada.

LINESEP

RECORD_DELIMITER

CSV

Um ou mais caracteres que separam registros em um arquivo de entrada.

QUOTE

FIELD_OPTIONALLY_ENCLOSED_BY

CSV

Caractere usado para delimitar as cadeias de caracteres.

NULLVALUE

NULL_IF

CSV

String usada para converter de e para SQL NULL.

DATEFORMAT

DATE_FORMAT

CSV

String que define o formato dos valores de data nos arquivos de dados a serem carregados.

TIMESTAMPFORMAT

TIMESTAMP_FORMAT

CSV

String que define o formato dos valores de carimbo de data/hora nos arquivos de dados a serem carregados.

Se o parâmetro usado não estiver na lista, a API gera um erro.

SPRKPY1088

Mensagem: Os valores de pyspark.sql.readwriter.DataFrameWriter.option no Snowpark podem ser diferentes, portanto, pode ser necessária uma validação.

Categoria: Aviso

Descrição

Os valores de pyspark.sql.readwriter.DataFrameWriter.option no Snowpark podem ser diferentes, portanto, pode ser necessária uma validação para garantir que o comportamento esteja correto.

Cenários

Há alguns cenários, dependendo da opção ser suportada ou não, ou do formato usado para gravar o arquivo.

Cenário 1

Entrada

Veja abaixo um exemplo de uso da opção de método, adicionando uma opção sep, que atualmente é suportada.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])

df.write.option("sep", ",").csv("some_path")
Copy

Saída

A ferramenta adiciona EWI SPRKPY1088 indicando que se trata de uma validação obrigatória.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])
#EWI: SPRKPY1088 => The pyspark.sql.readwriter.DataFrameWriter.option values in Snowpark may be different, so required validation might be needed.
df.write.option("sep", ",").csv("some_path")
Copy

Correção recomendada

O Snowpark API oferece suporte a esse parâmetro, portanto, a única ação pode ser verificar o comportamento após a migração. Consulte a tabela Equivalências para ver os parâmetros compatíveis.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])
#EWI: SPRKPY1088 => The pyspark.sql.readwriter.DataFrameWriter.option values in Snowpark may be different, so required validation might be needed.
df.write.option("sep", ",").csv("some_path")
Copy
Cenário 2

Entrada

Aqui o cenário mostra o uso da opção, mas adiciona uma opção de cabeçalho, que é não suportada.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])

df.write.option("header", True).csv("some_path")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1088 indicando que a validação é necessária.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])
#EWI: SPRKPY1088 => The pyspark.sql.readwriter.DataFrameWriter.option values in Snowpark may be different, so required validation might be needed.
df.write.option("header", True).csv("some_path")
Copy

Correção recomendada

Para esse cenário, é recomendável avaliar as opções de tipo de formato do Snowpark para ver se é possível alterá-lo de acordo com suas necessidades. Além disso, verifique o comportamento após a alteração.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])
#EWI: SPRKPY1088 => The pyspark.sql.readwriter.DataFrameWriter.option values in Snowpark may be different, so required validation might be needed.
df.write.csv("some_path")
Copy
Cenário 3

Entrada

Esse cenário adiciona uma opção sep, que é suportada e usa o método JSON.

  • Observação: esse cenário também se aplica a PARQUET.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])

df.write.option("sep", ",").json("some_path")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1088 indicando que a validação é necessária.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])
#EWI: SPRKPY1088 => The pyspark.sql.readwriter.DataFrameWriter.option values in Snowpark may be different, so required validation might be needed.
df.write.option("sep", ",").json("some_path")
Copy

Correção recomendada

O formato de arquivo JSON não é compatível com o parâmetro sep, portanto, é recomendável avaliar as opções de tipo de formato do Snowpark para ver se é possível alterá-lo de acordo com suas necessidades. Além disso, verifique o comportamento após a alteração.

df = spark.createDataFrame([(100, "myVal")], ["ID", "Value"])
#EWI: SPRKPY1088 => The pyspark.sql.readwriter.DataFrameWriter.option values in Snowpark may be different, so required validation might be needed.
df.write.json("some_path")
Copy

Recomendações adicionais

  • Como existem alguns parâmetros não suportados, recomenda-se verificar a tabela de equivalências e verificar o comportamento após a transformação.

  • Tabela de equivalências:

Opção PySpark

Opção SnowFlake

Formatos de arquivo suportados

Descrição

SEP

FIELD_DELIMITER

CSV

Um ou mais caracteres de byte único ou de vários bytes que separam os campos em um arquivo de entrada.

LINESEP

RECORD_DELIMITER

CSV

Um ou mais caracteres que separam registros em um arquivo de entrada.

QUOTE

FIELD_OPTIONALLY_ENCLOSED_BY

CSV

Caractere usado para delimitar as cadeias de caracteres.

NULLVALUE

NULL_IF

CSV

String usada para converter de e para SQL NULL.

DATEFORMAT

DATE_FORMAT

CSV

String que define o formato dos valores de data nos arquivos de dados a serem carregados.

TIMESTAMPFORMAT

TIMESTAMP_FORMAT

CSV

String que define o formato dos valores de carimbo de data/hora nos arquivos de dados a serem carregados.

Se o parâmetro usado não estiver na lista, a API gera um erro.

SPRKPY1011

Mensagem: pyspark.sql.dataframe.DataFrameStatFunctions.approxQuantile tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.dataframe.DataFrameStatFunctions.approxQuantile que tem uma solução alternativa.

Cenário

Entrada

É importante entender que o Pyspark usa duas funções approxQuantile diferentes; aqui usamos a versão DataFrameStatFunctions approxQuantile.

import tempfile
from pyspark.sql import SparkSession, DataFrameStatFunctions
spark = SparkSession.builder.getOrCreate()
data = [['Q1', 300000],
        ['Q2', 60000],
        ['Q3', 500002],
        ['Q4', 130000]]

columns = ['Quarter', 'Gain']
df = spark.createDataFrame(data, columns)
aprox_quantille = DataFrameStatFunctions(df).approxQuantile('Gain', [0.25, 0.5, 0.75], 0)
print(aprox_quantille)
Copy

Saída

O SMA retorna o EWI SPRKPY1011 sobre a linha em que approxQuantile é usado, para que você possa identificar onde corrigir.

import tempfile
from snowflake.snowpark import Session, DataFrameStatFunctions
spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 300000],
        ['Q2', 60000],
        ['Q3', 500002],
        ['Q4', 130000]]

columns = ['Quarter', 'Gain']
df = spark.createDataFrame(data, columns)
#EWI: SPRKPY1011 => pyspark.sql.dataframe.DataFrameStatFunctions.approxQuantile has a workaround, see documentation for more info
aprox_quantille = DataFrameStatFunctions(df).approxQuantile('Gain', [0.25, 0.5, 0.75], 0)
Copy

Correção recomendada

Você pode usar o método aproxQuantile do Snowpark. Alguns parâmetros não correspondem, e por isso exigem ajustes manuais. Para o exemplo do código de saída, uma correção recomendada poderia ser:

from snowflake.snowpark import Session # remove DataFrameStatFunctions because is not required
...
df = spark.createDataFrame(data, columns)

aprox_quantille = df.stat.approx_quantile('Ammount', [0.25, 0.5, 0.75])
Copy

pyspark.sql.dataframe.DataFrame.approxQuantile relativeError parameter não existe no SnowPark.

Recomendações adicionais

SPRKPY1040

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.functions.explode tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.explode, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.explode que gera esse EWI. Neste exemplo, a função explode é usada para gerar uma linha por item de matriz para a coluna numbers.

df = spark.createDataFrame([("Alice", [1, 2, 3]), ("Bob", [4, 5]), ("Charlie", [6, 7, 8, 9])], ["name", "numbers"])
exploded_df = df.select("name", explode(df.numbers).alias("number"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1040 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([("Alice", [1, 2, 3]), ("Bob", [4, 5]), ("Charlie", [6, 7, 8, 9])], ["name", "numbers"])
#EWI: SPRKPY1040 => pyspark.sql.functions.explode has a workaround, see documentation for more info
exploded_df = df.select("name", explode(df.numbers).alias("number"))
Copy

Correção recomendada

Como solução alternativa, você pode importar o pacote snowpark_extensions, que fornece uma extensão para a função explode.

import snowpark_extensions

df = spark.createDataFrame([("Alice", [1, 2, 3]), ("Bob", [4, 5]), ("Charlie", [6, 7, 8, 9])], ["name", "numbers"])
exploded_df = df.select("name", explode(df.numbers).alias("number"))
Copy

Recomendações adicionais

SPRKPY1074

Mensagem: O arquivo tem indentação mista (espaços e tabulações).

Categoria: Erro de análise.

Descrição

Esse problema aparece quando a ferramenta detecta que o arquivo tem um recuo misto. Isso significa que o arquivo tem uma combinação de espaços e tabulações para recuar as linhas de código.

Cenário

Entrada

No Pyspark, você pode misturar espaços e tabulações para o nível de identificação.

def foo():
    x = 5 # spaces
    y = 6 # tab
Copy

Saída

O SMA não pode lidar com marcadores de recuo mistos. Quando isso é detectado em um arquivo de código python, o SMA adiciona o EWI SPRKPY1074 na primeira linha.

## EWI: SPRKPY1074 => File has mixed indentation (spaces and tabs).
## This file was not converted, so it is expected to still have references to the Spark API
def foo():
    x = 5 # spaces
    y = 6 # tabs
Copy

Correção recomendada

A solução é fazer com que todos os símbolos de recuo sejam iguais.

def foo():
  x = 5 # tab
  y = 6 # tab
Copy

Recomendações adicionais

SPRKPY1025

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.functions.ntile tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.ntile, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.ntile que gera esse EWI. Neste exemplo, a função ntile é usada para dividir as linhas em 3 compartimentos.

df = spark.createDataFrame([("Alice", 50), ("Bob", 30), ("Charlie", 60), ("David", 90), ("Eve", 70), ("Frank", 40)], ["name", "score"])
windowSpec = Window.orderBy("score")
df_with_ntile = df.withColumn("bucket", ntile(3).over(windowSpec))
Copy

Saída

O SMA adiciona o EWI SPRKPY1025 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([("Alice", 50), ("Bob", 30), ("Charlie", 60), ("David", 90), ("Eve", 70), ("Frank", 40)], ["name", "score"])
windowSpec = Window.orderBy("score")
#EWI: SPRKPY1025 => pyspark.sql.functions.ntile has a workaround, see documentation for more info
df_with_ntile = df.withColumn("bucket", ntile(3).over(windowSpec))
Copy

Correção recomendada

O Snowpark tem uma função ntile equivalente, mas o argumento passado para ela deve ser uma coluna. Como solução alternativa, você pode converter o argumento literal em uma coluna usando a função snowflake.snowpark.functions.lit.

df = spark.createDataFrame([("Alice", 50), ("Bob", 30), ("Charlie", 60), ("David", 90), ("Eve", 70), ("Frank", 40)], ["name", "score"])
windowSpec = Window.orderBy("score")
df_with_ntile = df.withColumn("bucket", ntile(lit(3)).over(windowSpec))
Copy

Recomendações adicionais

SPRKPY1087

Mensagem: A função pyspark.sql.dataframe.DataFrame.writeTo não é suportada, mas tem uma solução alternativa.

Categoria: Aviso.

Descrição

A função pyspark.sql.dataframe.DataFrame.writeTo não é suportada. A solução alternativa é usar o método do Snowpark DataFrameWriter SaveAsTable.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.dataframe.DataFrame.writeTo, o dataframe df é gravado em uma tabela com o nome Personal_info.

df = spark.createDataFrame([["John", "Berry"], ["Rick", "Berry"], ["Anthony", "Davis"]],
                                 schema=["FIRST_NAME", "LAST_NAME"])

df.writeTo("Personal_info")
Copy

Saída

O SMA adiciona o EWI SPRKPY1087 ao código de saída para informar que essa função não é compatível, mas tem uma solução alternativa.

df = spark.createDataFrame([["John", "Berry"], ["Rick", "Berry"], ["Anthony", "Davis"]],
                                 schema=["FIRST_NAME", "LAST_NAME"])

#EWI: SPRKPY1087 => pyspark.sql.dataframe.DataFrame.writeTo is not supported, but it has a workaround.
df.writeTo("Personal_info")
Copy

Correção recomendada

A solução alternativa é usar o método do Snowpark DataFrameWriter SaveAsTable.

df = spark.createDataFrame([["John", "Berry"], ["Rick", "Berry"], ["Anthony", "Davis"]],
                                 schema=["FIRST_NAME", "LAST_NAME"])

df.write.saveAsTable("Personal_info")
Copy

Recomendações adicionais

SPRKPY1035

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.functions.reverse tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.reverse, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.reverse que gera esse EWI. Neste exemplo, a função reverse é usada para inverter cada cadeia de caracteres da coluna word.

df = spark.createDataFrame([("hello",), ("world",)], ["word"])
df_reversed = df.withColumn("reversed_word", reverse(df["word"]))
df_reversed = df.withColumn("reversed_word", reverse("word"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1035 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([("hello",), ("world",)], ["word"])
#EWI: SPRKPY1035 => pyspark.sql.functions.reverse has a workaround, see documentation for more info
df_reversed = df.withColumn("reversed_word", reverse(df["word"]))
#EWI: SPRKPY1035 => pyspark.sql.functions.reverse has a workaround, see documentation for more info
df_reversed = df.withColumn("reversed_word", reverse("word"))
Copy

Correção recomendada

Como solução alternativa, você pode importar o pacote snowpark_extensions, que fornece uma extensão para a função reverse.

import snowpark_extensions

df = spark.createDataFrame([("hello",), ("world",)], ["word"])
df_reversed = df.withColumn("reversed_word", reverse(df["word"]))
df_reversed = df.withColumn("reversed_word", reverse("word"))
Copy

Recomendações adicionais

SPRKPY1064

Mensagem: O elemento _ Spark _ não se aplica, pois o snowflake usa o mecanismo snowpipe.

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso de qualquer elemento da biblioteca pyspark.streaming:

Cenário

Entrada

Abaixo está um exemplo com um dos elementos que acionam esse EWI.

from pyspark.streaming.listener import StreamingListener

var = StreamingListener.Java
var.mro()

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])
df.show()
Copy

Saída

O SMA adiciona o EWI SPRKPY1064 no código de saída para que você saiba que essa função não se aplica.

#EWI: SPRKPY1064 => The element does not apply since snowflake uses snowpipe mechanism instead.

var = StreamingListener.Java
var.mro()

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])
df.show()
Copy

Correção recomendada

O SMA remove a instrução de importação e adiciona o problema ao inventário Issues.csv, removendo todos os usos do elemento Spark.

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])
df.show()
Copy

Recomendações adicionais

SPRKPY1050

Mensagem: pyspark.conf.SparkConf.set tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.conf.SparkConf.set que tem uma solução alternativa.

Cenário

Entrada

Abaixo está um exemplo que define uma variável usando conf.set.

conf = SparkConf().setAppName('my_app')

conf.set("spark.storage.memoryFraction", "0.5")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1050 indicando que uma solução alternativa pode ser implementada.

conf = SparkConf().setAppName('my_app')

#EWI: SPRKPY1050 => pyspark.conf.SparkConf.set has a workaround, see documentation for more info
conf.set("spark.storage.memoryFraction", "0.5")
Copy

Correção recomendada

SparkConf.set é usado para definir uma configuração usada somente pelo Pyspark e não se aplica ao Snowpark. Você pode remover ou comentar o código

#conf.set("spark.storage.memoryFraction", "0.5")
Copy

Recomendações adicionais

SPRKPY1001

Message : Esta seção de código tem erros de análise

Category : Erro de análise.

Descrição

Um erro de análise é relatado pelo Snowpark Migration Accelerator (SMA) quando ele não consegue ler ou entender corretamente o código em um arquivo (não consegue «analisar» corretamente o arquivo). Esse código de problema aparece quando um arquivo tem um ou mais erros de análise.

Cenário

Entrada: A mensagem EWI é exibida quando o código tem sintaxe inválida, por exemplo:

def foo():
    x = %%%%%%1###1
Copy

Saída: O SMA encontra um erro de análise e comenta o erro de análise adicionando a mensagem EWI correspondente:

def foo():
    x
## EWI: SPRKPY1101 => Unrecognized or invalid CODE STATEMENT @(2, 7). Last valid token was 'x' @(2, 5), failed token '=' @(2, 7)
##      = %%%%%%1###1
Copy

Recomendações adicionais

  • Verifique se o arquivo contém código Python válido. (Você pode usar o arquivo issues.csv para localizar todos os arquivos com esse código EWI para determinar quais arquivos não foram processados pela ferramenta devido a erros de análise) Muitos erros de análise ocorrem porque apenas parte do código é inserida na ferramenta, portanto, é importante garantir que o código seja executado na fonte. Se for válido, informe que encontrou um erro de análise usando a opção de Relatar um problema no SMA. Inclua a linha de código que estava causando o erro de análise na descrição quando registrar esse problema.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1021

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.functions.last tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.last, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.last que gera esse EWI. Neste exemplo, a função last é usada para obter o último valor **** para cada nome.

df = spark.createDataFrame([("Alice", 1), ("Bob", 2), ("Charlie", 3), ("Alice", 4), ("Bob", 5)], ["name", "value"])
df_grouped = df.groupBy("name").agg(last("value").alias("last_value"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1021 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([("Alice", 1), ("Bob", 2), ("Charlie", 3), ("Alice", 4), ("Bob", 5)], ["name", "value"])
#EWI: SPRKPY1021 => pyspark.sql.functions.last has a workaround, see documentation for more info
df_grouped = df.groupBy("name").agg(last("value").alias("last_value"))
Copy

Correção recomendada

Como solução alternativa, você pode usar a função Snowflake LAST_VALUE. Para invocar essa função do Snowpark, use a função snowflake.snowpark.functions.call_builtin e passe a cadeia de cadeia de caracteres last_value como o primeiro argumento e a coluna correspondente como o segundo argumento. Se estava usando o nome da coluna na função last, deve convertê-lo em uma coluna ao chamar a função call_builtin.

df = spark.createDataFrame([("Alice", 1), ("Bob", 2), ("Charlie", 3), ("Alice", 4), ("Bob", 5)], ["name", "value"])
df_grouped = df.groupBy("name").agg(call_builtin("last_value", col("value")).alias("last_value"))
Copy

Recomendações adicionais


descrição: >- O parâmetro mode nos métodos CSV, JSON e PARQUET é transformado em overwrite


SPRKPY1070

Mensagem: O argumento mode é transformado em overwrite, verifica o valor da variável e define o valor bool correspondente.

Categoria: Aviso

Descrição

Quando há um uso de:

A ferramenta analisa o parâmetro mode para determinar se o valor é overwrite.

Cenários

Cenário 1

Código de entrada

Para esse cenário, a ferramenta detecta que o parâmetro mode pode definir o valor bool correspondente.

df.write.csv(file_path, mode="overwrite")
Copy

Código de saída:

A ferramenta SMA analisa o parâmetro mode, determina que o valor é overwrite e define o valor bool correspondente

df.write.csv(file_path, format_type_options = dict(compression = "None"), overwrite = True)
Copy

Correção recomendada

Não há uma correção recomendada para esse cenário porque a ferramenta realizou a transformação correspondente.

Cenário 2:

Código de entrada

Nesse cenário, a ferramenta não pode validar se o valor é overwrite.

df.write.csv(file_path, mode=myVal)
Copy

Código de saída:

O SMA adiciona uma mensagem EWI indicando que o parâmetro mode foi transformado em “overwrite”, mas também serve para que você saiba que é melhor verificar o valor da variável e definir o valor bool correto.

#EWI: SPRKPY1070 => The 'mode' argument is transformed to 'overwrite', check the variable value and set the corresponding bool value.
df.write.csv(file_path, format_type_options = dict(compression = "None"), overwrite = myVal)
Copy

Correção recomendada

Verifique o valor do parâmetro mode e adicione o valor correto para o parâmetro overwrite.

df.write.csv(file_path, format_type_options = dict(compression = "None"), overwrite = True)
Copy

Recomendações adicionais

SPRKPY1083

Mensagem: A função pyspark.sql.readwriter.DataFrameWriter.save não é suportada. Uma solução alternativa é usar o método copy_into_location do Snowpark DataFrameWriter.

Categoria: Aviso

Descrição

A função pyspark.sql.readwriter.DataFrameWriter.save não é suportada. A solução alternativa é usar os métodos do Snowpark DataFrameWriter.

Cenários

A assinatura spark para esse método DataFrameWriter. save(path, format, mode, partitionBy, **options) não existe no Snowpark. Portanto, qualquer uso da função load terá um EWI no código de saída.

Cenário 1

Código de entrada

Abaixo está um exemplo que tenta salvar dados no formato CSV.

path_csv_file = "/path/to/file.csv"

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = my_session.createDataFrame(data, schema=["Name", "Age", "City"])

df.write.save(path_csv_file, format="csv")
df.write.save(path_csv_file, format="csv", mode="overwrite")
df.write.save(path_csv_file, format="csv", mode="overwrite", lineSep="\r\n", dateFormat="YYYY/MM/DD")
df.write.save(path_csv_file, format="csv", mode="overwrite", partitionBy="City", lineSep="\r\n", dateFormat="YYYY/MM/DD")
Copy

Código de saída

A ferramenta adiciona esse EWI SPRKPY1083 no código de saída para que você saiba que essa função não é compatível com o Snowpark, mas há uma solução alternativa.

path_csv_file = "/path/to/file.csv"

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = my_session.createDataFrame(data, schema=["Name", "Age", "City"])

#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_csv_file, format="csv")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_csv_file, format="csv", mode="overwrite")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_csv_file, format="csv", mode="overwrite", lineSep="\r\n", dateFormat="YYYY/MM/DD")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_csv_file, format="csv", mode="overwrite", partitionBy="City", lineSep="\r\n", dateFormat="YYYY/MM/DD")
Copy

Correção recomendada

Como solução alternativa, você pode usar os métodos do Snowpark DataFrameWriter.

  • Correção dos parâmetros path e format:

    • Substitua o método load pelo método csv ou copy_into_location.

    • Se estiver usando o método copy_into_location, precisará especificar o formato com o parâmetro file_format_type.

    • O primeiro parâmetro path deve estar em um estágio para fazer uma equivalência com o Snowpark.

Abaixo está um exemplo que cria um estágio temporal e coloca o arquivo nele, depois chama um dos métodos mencionados acima.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Stage creation

temp_stage = f'{Session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
my_session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {temp_stage}').show()
my_session.file.put(f"file:///path/to/file.csv", f"@{temp_stage}")
stage_file_path = f"{temp_stage}file.csv"

## Using csv method
df.write.csv(stage_file_path)

## Using copy_into_location method
df.write.copy_into_location(stage_file_path, file_format_type="csv")
Copy

Abaixo está um exemplo que adiciona à cadeia em margarida o método mode com overwrite como parâmetro.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Using csv method
df.write.mode("overwrite").csv(temp_stage)

## Using copy_into_location method
df.write.mode("overwrite").copy_into_location(temp_stage, file_format_type="csv")
Copy
  • Correção do parâmetro partitionBy:

Abaixo está um exemplo que usou o parâmetro partition_by do método CSV.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Using csv method
df.write.csv(temp_stage, partition_by="City")

## Using copy_into_location method
df.write.copy_into_location(temp_stage, file_format_type="csv", partition_by="City")
Copy
  • Correção do parâmetro options:

As opções entre o spark e o snowpark não são as mesmas. Nesse caso, lineSep e dateFormat são substituídos por RECORD_DELIMITER e DATE_FORMAT, a seção Additional recommendations tem uma tabela com todas as equivalências.

Abaixo está um exemplo que cria um dicionário com RECORD_DELIMITER e DATE_FORMAT e chama o método options com esse dicionário.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])
optionsParam = {"RECORD_DELIMITER": "\r\n", "DATE_FORMAT": "YYYY/MM/DD"}

## Using csv method
df.write.csv(stage, format_type_options=optionsParam)

## Using copy_into_location method
df.write.csv(stage, file_format_type="csv", format_type_options=optionsParam)
Copy

Cenário 2

Código de entrada

Abaixo está um exemplo que tenta salvar dados no formato JSON.

path_json_file = "/path/to/file.json"

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

df.write.save(path_json_file, format="json")
df.write.save(path_json_file, format="json", mode="overwrite")
df.write.save(path_json_file, format="json", mode="overwrite", dateFormat="YYYY/MM/DD", timestampFormat="YYYY-MM-DD HH24:MI:SS.FF3")
df.write.save(path_json_file, format="json", mode="overwrite", partitionBy="City", dateFormat="YYYY/MM/DD", timestampFormat="YYYY-MM-DD HH24:MI:SS.FF3")
Copy

Código de saída

A ferramenta adiciona esse EWI SPRKPY1083 no código de saída para que você saiba que essa função não é compatível com o Snowpark, mas há uma solução alternativa.

path_json_file = "/path/to/file.json"

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_json_file, format="json")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_json_file, format="json", mode="overwrite")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_json_file, format="json", mode="overwrite", dateFormat="YYYY/MM/DD", timestampFormat="YYYY-MM-DD HH24:MI:SS.FF3")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_json_file, format="json", mode="overwrite", partitionBy="City", dateFormat="YYYY/MM/DD", timestampFormat="YYYY-MM-DD HH24:MI:SS.FF3")
Copy

Correção recomendada

Como solução alternativa, você pode usar os métodos do Snowpark DataFrameReader.

  • Correção dos parâmetros path e format:

    • Substitua o método load pelo método json ou copy_into_location

    • Se estiver usando o método copy_into_location, precisará especificar o formato com o parâmetro file_format_type.

    • O primeiro parâmetro path deve estar em um estágio para fazer uma equivalência com o Snowpark.

Abaixo está um exemplo que cria um estágio temporal e coloca o arquivo nele, depois chama um dos métodos mencionados acima.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Stage creation

temp_stage = f'{Session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
my_session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {temp_stage}').show()
my_session.file.put(f"file:///path/to/file.json", f"@{temp_stage}")
stage_file_path = f"{temp_stage}file.json"

## Using json method
df.write.json(stage_file_path)

## Using copy_into_location method
df.write.copy_into_location(stage_file_path, file_format_type="json")
Copy

Abaixo está um exemplo que adiciona à cadeia em margarida o método mode com overwrite como parâmetro.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Using json method
df.write.mode("overwrite").json(temp_stage)

## Using copy_into_location method
df.write.mode("overwrite").copy_into_location(temp_stage, file_format_type="json")
Copy
  • Correção do parâmetro partitionBy:

Abaixo está um exemplo que usou o parâmetro partition_by do método CSV.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Using json method
df.write.json(temp_stage, partition_by="City")

## Using copy_into_location method
df.write.copy_into_location(temp_stage, file_format_type="json", partition_by="City")
Copy
  • Correção do parâmetro options:

As opções entre o spark e o snowpark não são as mesmas. Nesse caso, dateFormat e timestampFormat são substituídos por DATE_FORMAT e TIMESTAMP_FORMAT, a seção Additional recommendations tem uma tabela com todas as equivalências.

Abaixo está um exemplo que cria um dicionário com DATE_FORMAT e TIMESTAMP_FORMAT e chama o método options com esse dicionário.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])
optionsParam = {"DATE_FORMAT": "YYYY/MM/DD", "TIMESTAMP_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3"}

## Using json method
df.write.json(stage, format_type_options=optionsParam)

## Using copy_into_location method
df.write.copy_into_location(stage, file_format_type="json", format_type_options=optionsParam)
Copy

Cenário 3

Código de entrada

Abaixo está um exemplo que tenta salvar dados no formato PARQUET.

path_parquet_file = "/path/to/file.parquet"

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

df.write.save(path_parquet_file, format="parquet")
df.write.save(path_parquet_file, format="parquet", mode="overwrite")
df.write.save(path_parquet_file, format="parquet", mode="overwrite", pathGlobFilter="*.parquet")
df.write.save(path_parquet_file, format="parquet", mode="overwrite", partitionBy="City", pathGlobFilter="*.parquet")
Copy

Código de saída

A ferramenta adiciona esse EWI SPRKPY1083 no código de saída para que você saiba que essa função não é compatível com o Snowpark, mas há uma solução alternativa.

path_parquet_file = "/path/to/file.parquet"

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_parquet_file, format="parquet")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_parquet_file, format="parquet", mode="overwrite")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_parquet_file, format="parquet", mode="overwrite", pathGlobFilter="*.parquet")
#EWI: SPRKPY1083 => The pyspark.sql.readwriter.DataFrameWriter.save function is not supported. A workaround is to use Snowpark DataFrameWriter copy_into_location method instead.
df.write.save(path_parquet_file, format="parquet", mode="overwrite", partitionBy="City", pathGlobFilter="*.parquet")
Copy

Correção recomendada

Como solução alternativa, você pode usar os métodos do Snowpark DataFrameReader.

  • Correção dos parâmetros path e format:

    • Substitua o método load pelo método parquet ou copy_into_location.

    • Se estiver usando o método copy_into_location, precisará especificar o formato com o parâmetro file_format_type.

    • O primeiro parâmetro path deve estar em um estágio para fazer uma equivalência com o Snowpark.

Abaixo está um exemplo que cria um estágio temporal e coloca o arquivo nele, depois chama um dos métodos mencionados acima.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Stage creation

temp_stage = f'{Session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
my_session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {temp_stage}').show()
my_session.file.put(f"file:///path/to/file.parquet", f"@{temp_stage}")
stage_file_path = f"{temp_stage}file.parquet"

## Using parquet method
df.write.parquet(stage_file_path)

## Using copy_into_location method
df.write.copy_into_location(stage, file_format_type="parquet")
Copy

Abaixo está um exemplo que adiciona à cadeia em margarida o método mode com overwrite como parâmetro.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Using parquet method
df.write.mode("overwrite").parquet(temp_stage)

## Using copy_into_location method
df.write.mode("overwrite").copy_into_location(stage, file_format_type="parquet")
Copy
  • Correção do parâmetro partitionBy:

Abaixo está um exemplo que usou o parâmetro partition_by do método parquet.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

## Using parquet method
df.write.parquet(temp_stage, partition_by="City")

## Using copy_into_location method
df.write.copy_into_location(stage, file_format_type="parquet", partition_by="City")
Copy
  • Correção do parâmetro options:

As opções entre spark e snowpark não são as mesmas. Nesse caso, pathGlobFilter é substituído por PATTERN, a seção Additional recommendations tem uma tabela com todas as equivalências.

Abaixo está um exemplo que cria um dicionário com PATTERN e chama o método options com esse dicionário.

data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]
df = spark.createDataFrame(data, schema=["Name", "Age", "City"])
optionsParam = {"PATTERN": "*.parquet"}

## Using parquet method
df.write.parquet(stage, format_type_options=optionsParam)

## Using copy_into_location method
df.write.copy_into_location(stage, file_format_type="parquet", format_type_options=optionsParam)
Copy

Recomendações adicionais

  • Leve em conta que as opções entre o spark e o snowpark não são as mesmas, mas podem ser mapeadas:

Opções do Spark

Valor possível

Equivalente do Snowpark

Descrição

header

Verdadeiro ou falso

SKIP_HEADER = 1 / SKIP_HEADER = 0

Para usar a primeira linha de um arquivo como nomes de colunas.

delimiter

Qualquer separador de campo de um ou vários caracteres

FIELD_DELIMITER

Para especificar caractere(s) único(s)/múltiplo(s) como separador para cada coluna/campo.

sep

Qualquer separador de campo de caractere único

FIELD_DELIMITER

Para especificar um único caractere como separador para cada coluna/campo.

encoding

UTF-8, UTF-16, etc…

ENCODING

Para decodificar os arquivos CSV pelo tipo de codificação fornecido. A codificação padrão é UTF-8

lineSep

Qualquer separador de linha de caractere único

RECORD_DELIMITER

Para definir o separador de linha que deve ser usado na análise de arquivos.

pathGlobFilter

Padrão de arquivo

PATTERN

Para definir um padrão para ler arquivos somente com nomes de arquivos que correspondam ao padrão.

recursiveFileLookup

Verdadeiro ou falso

N/A

Para examinar recursivamente um diretório para ler arquivos. O valor padrão dessa opção é False.

quote

Caractere único a ser citado

FIELD_OPTIONALLY_ENCLOSED_BY

Para citar campos/colunas que contêm campos em que o delimitador/separador pode fazer parte do valor. Esse caractere Para citar todos os campos quando usado com a opção quoteAll. O valor padrão dessa opção é aspas duplas («).

nullValue

Cadeia de caracteres para substituir null

NULL_IF

Para substituir os valores nulos pela cadeia de caracteres durante a leitura e gravação do dataframe.

dateFormat

Formato de data válido

DATE_FORMAT

Para definir uma cadeia de caracteres que indica um formato de data. O formato padrão é yyyy-MM-dd.

timestampFormat

Formato de carimbo de data/hora válido

TIMESTAMP_FORMAT

Para definir uma cadeia de caracteres que indica um formato de carimbo de data/hora. O formato padrão é yyyy-MM-dd “T’HH:mm:ss.

escape

Qualquer caractere único

ESCAPE

Para definir um único caractere como caractere de escape para substituir o caractere de escape padrão (\).

inferSchema

Verdadeiro ou falso

INFER_SCHEMA

Detecta automaticamente o esquema do arquivo

mergeSchema

Verdadeiro ou falso

N/A

Não é necessário no snowflake, pois isso acontece sempre que o infer_schema determina a estrutura do arquivo parquet

  • Para a opção modifiedBefore / modifiedAfter, você pode obter o mesmo resultado no Snowflake usando as colunas de metadados e, em seguida, adicionar um filtro como: df.filter(METADATA_FILE_LAST_MODIFIED > 'some_date').

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1044

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 2.4.0

Mensagem: pyspark.sql.functions.split tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.split, que tem uma solução alternativa.

Cenários

Há alguns cenários, dependendo da quantidade de parâmetros passados para o método.

Cenário 1

Entrada

Abaixo está um exemplo quando a função split tem apenas os parâmetros str e pattern

F.split('col', '\\|')
Copy

Saída

A ferramenta mostra o EWI SPRKPY1044 indicando que há uma solução alternativa.

#EWI: SPRKPY1044 => pyspark.sql.functions.split has a workaround, see the documentation for more info
F.split('col', '\\|')
Copy

Correção recomendada

Como solução alternativa, você pode chamar a função snowflake.snowpark.functions.lit com o parâmetro pattern e enviá-la para a divisão.

F.split('col', lit('\\|'))
## the result of lit will be sent to the split function
Copy

Cenário 2

Entrada

Abaixo está outro exemplo quando a função split tem os parâmetros str, pattern e limit.

F.split('col', '\\|', 2)
Copy

Saída

A ferramenta mostra o EWI SPRKPY1044 indicando que há uma solução alternativa.

#EWI: SPRKPY1044 => pyspark.sql.functions.split has a workaround, see the documentation for more info
F.split('col', '\\|', 2)
Copy

Correção recomendada

Esse cenário específico não é suportado.

Recomendações adicionais

SPRKPY1015

Mensagem: pyspark.sql.functions.atanh tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.atanh, que tem uma solução alternativa.

Cenário

Entrada

Nesse exemplo, o pyspark calcula o atanh para um dataframe usando pyspark.sql.functions.atanh.

from pyspark.sql import SparkSession
from pyspark.sql.functions import atanh
spark = SparkSession.builder.getOrCreate()
data = [['V1', 0.14],
        ['V2', 0.32],
        ['V3', 0.4],
        ['V4', -0.36]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
df_result = df.withColumn("atanh_value", atanh(df["value"]))
Copy

Saída

SMA retorna o EWI SPRKPY1015 sobre a linha em que atanh é usado, para que você possa usar para identificar onde corrigir.

from snowflake.snowpark import Session

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['V1', 0.14],
        ['V2', 0.32],
        ['V3', 0.4],
        ['V4', -0.36]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
#EWI: SPRKPY1015 => pyspark.sql.functions.atanh has a workaround, see documentation for more info
df_result = df.withColumn("atanh_value", atanh(df["value"]))
Copy

Correção recomendada

Não há implementação direta do «atanh», mas, em vez disso, pode-se usar «call_function «, usando «atanh» como o primeiro parâmetro e colName como o segundo.

import snowflake.snowpark as snowpark
from snowflake.snowpark import Session
from snowflake.snowpark.functions import call_function, col

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['V1', 0.14],
        ['V2', 0.32],
        ['V3', 0.4],
        ['V4', -0.36]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
df_result = df.select(call_function('atanh', col('value')))
Copy

Recomendações adicionais

SPRKPY1005

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 4.8.0

Message : pyspark.conf.SparkConf não é necessário

Category : Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.conf.SparkConf que não é necessário.

Cenário

Entrada

SparkConf pode ser chamado sem parâmetros ou com loadDefaults.

from pyspark import SparkConf

my_conf = SparkConf(loadDefaults=True)
Copy

Saída

Em ambos os casos (com ou sem parâmetros), o SMA cria um objeto Session.builder do Snowpark:

#EWI: SPRKPY1005 => pyspark.conf.SparkConf is not required
#from pyspark import SparkConf
pass

#EWI: SPRKPY1005 => pyspark.conf.SparkConf is not required
my_conf = Session.builder.configs({"user" : "my_user", "password" : "my_password", "account" : "my_account", "role" : "my_role", "warehouse" : "my_warehouse", "database" : "my_database", "schema" : "my_schema"}).create()
Copy

Recomendações adicionais

  • Esse é um parâmetro desnecessário que está sendo removido com a inserção de um comentário de aviso. Não deve haver nenhuma ação adicional por parte do usuário.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1054

Mensagem: pyspark.sql.readwriter.DataFrameReader.format não é suportado.

Categoria: Aviso.

Descrição

Esse problema aparece quando o pyspark.sql.readwriter.DataFrameReader.format tem um argumento que não é suportado pelo Snowpark.

Cenários

Há alguns cenários, dependendo do tipo de formato que você está tentando carregar. Pode ser um formato suportado ou não suportado.

Cenário 1

Entrada

A ferramenta analisa o tipo de formato que está tentando carregar; os formatos compatíveis são:

  • Csv

  • JSON

  • Parquet

  • Orc

O exemplo abaixo mostra como a ferramenta transforma o método format ao passar um valor Csv.

from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()

df1 = spark.read.format('csv').load('/path/to/file')
Copy

Saída

A ferramenta transforma o método format em uma chamada de método Csv.

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()

df1 = spark.read.csv('/path/to/file')
Copy

Correção recomendada

Nesse caso, a ferramenta não mostra o EWI, o que significa que não há necessidade de correção.

Cenário 2

Entrada

O exemplo abaixo mostra como a ferramenta transforma o método format ao passar um valor Jdbc.

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()

df2 = spark.read.format('jdbc') \
    .option("driver", "com.mysql.cj.jdbc.Driver") \
    .option("url", "jdbc:mysql://localhost:3306/emp") \
    .option("dbtable", "employee") \
    .option("user", "root") \
    .option("password", "root") \
    .load()
Copy

Saída

A ferramenta mostra o EWI SPRKPY1054 indicando que o valor «jdbc» não é compatível.

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()

#EWI: SPRKPY1054 => pyspark.sql.readwriter.DataFrameReader.format with argument value "jdbc" is not supported.
#EWI: SPRKPY1002 => pyspark.sql.readwriter.DataFrameReader.load is not supported

df2 = spark.read.format('jdbc') \
    .option("driver", "com.mysql.cj.jdbc.Driver") \
    .option("url", "jdbc:mysql://localhost:3306/emp") \
    .option("dbtable", "employee") \
    .option("user", "root") \
    .option("password", "root") \
    .load()
Copy

Correção recomendada

Para os cenários não suportados, não há nenhuma correção específica, pois isso depende dos arquivos que estão tentando ser lidos.

Cenário 3

Entrada

O exemplo abaixo mostra como a ferramenta transforma o método format ao passar um CSV, mas usando uma variável.

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()

myFormat = 'csv'
df3 = spark.read.format(myFormat).load('/path/to/file')
Copy

Saída

Como a ferramenta não consegue determinar o valor da variável em tempo de execução, mostra o EWI SPRKPY1054 indicando que o valor «» não é suportado.

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()

myFormat = 'csv'
#EWI: SPRKPY1054 => pyspark.sql.readwriter.DataFrameReader.format with argument value "" is not supported.
#EWI: SPRKPY1002 => pyspark.sql.readwriter.DataFrameReader.load is not supported
df3 = spark.read.format(myFormat).load('/path/to/file')
Copy

Correção recomendada

Como solução alternativa, você pode verificar o valor da variável e adicioná-lo como uma cadeia de caracteres à chamada format.

Recomendações adicionais

SPRKPY1060

Mensagem: O mecanismo de autenticação é connection.json (modelo fornecido).

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.conf.SparkConf.

Cenário

Entrada

Como o mecanismo de autenticação é diferente no Snowpark, a ferramenta remove os usos e cria um arquivo de configuração de conexão (connection.json) em vez disso.

from pyspark import SparkConf

my_conf = SparkConf(loadDefaults=True)
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1060 indicando que o mecanismo de autenticação é diferente.

#EWI: SPRKPY1002 => pyspark.conf.SparkConf is not supported
#EWI: SPRKPY1060 => The authentication mechanism is connection.json (template provided).
#my_conf = Session.builder.configs(connection_parameter).getOrCreate()

my_conf = None
Copy

Correção recomendada

Para criar uma conexão, é necessário preencher as informações no arquivo connection.json.

{
  "user": "<USER>",
  "password": "<PASSWORD>",
  "account": "<ACCOUNT>",
  "role": "<ROLE>",
  "warehouse": "<WAREHOUSE>",
  "database": "<DATABASE>",
  "schema": "<SCHEMA>"
}
Copy

Recomendações adicionais

SPRKPY1031

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core 2.7.0

Mensagem: pyspark.sql.column.Column.contains tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.column.Column.contains, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.column.Column.contains que gera esse EWI. Neste exemplo, a função contains é usada para filtrar as linhas em que a coluna «City» contém a substring «New».

df = spark.createDataFrame([("Alice", "New York"), ("Bob", "Los Angeles"), ("Charlie", "Chicago")], ["Name", "City"])
df_filtered = df.filter(col("City").contains("New"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1031 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([("Alice", "New York"), ("Bob", "Los Angeles"), ("Charlie", "Chicago")], ["Name", "City"])
#EWI: SPRKPY1031 => pyspark.sql.column.Column.contains has a workaround, see documentation for more info
df_filtered = df.filter(col("City").contains("New"))
Copy

Correção recomendada

Como solução alternativa, você pode usar a função snowflake.snowpark.functions.contains passando a coluna como o primeiro argumento e o elemento a ser pesquisado como o segundo argumento. Se o elemento a ser pesquisado for um valor literal, ele deverá ser convertido em uma expressão de coluna usando a função lit.

from snowflake.snowpark import functions as f
df = spark.createDataFrame([("Alice", "New York"), ("Bob", "Los Angeles"), ("Charlie", "Chicago")], ["Name", "City"])
df_filtered = df.filter(f.contains(col("City"), f.lit("New")))
Copy

Recomendações adicionais

SPRKPY1020

Mensagem: pyspark.sql.functions.instr tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.instr, que tem uma solução alternativa.

Cenário

Entrada

Aqui está um exemplo básico de uso do pyspark instr:

from pyspark.sql import SparkSession
from pyspark.sql.functions import instr
spark = SparkSession.builder.getOrCreate()
df = spark.createDataFrame([('abcd',)], ['test',])
df.select(instr(df.test, 'cd').alias('result')).collect()
Copy

Saída:

O SMA retorna o EWI SPRKPY1020 sobre a linha em que o instr é usado, para que você possa identificar onde corrigir.

from snowflake.snowpark import Session

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
df = spark.createDataFrame([('abcd',)], ['test',])
#EWI: SPRKPY1020 => pyspark.sql.functions.instr has a workaround, see documentation for more info
df.select(instr(df.test, 'cd').alias('result')).collect()
Copy

Correção recomendada

É necessária uma alteração manual usando a função charindex e alterando a ordem dos dois primeiros parâmetros.

import snowflake.snowpark as snowpark
from snowflake.snowpark import Session
from snowflake.snowpark.functions import charindex, lit

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
df = spark.createDataFrame([('abcd',)], ['test',])
df.select(charindex(lit('cd'), df.test).as_('result')).show()
Copy

Recomendações adicionais

SPRKPY1071

Mensagem: A função pyspark.rdd.RDD.getNumPartitions não é necessária no Snowpark. Portanto, você deve remover todas as referências.

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta encontra o uso da função pyspark.rdd.RDD.getNumPartitions. O Snowflake usa o mecanismo de microparticionamento, portanto, o uso dessa função não é necessário.

Cenário

Entrada

O getNumPartitions retorna a quantidade de partições em um RDD.

df = spark.createDataFrame([('2015-04-08',), ('5',), [Row(a=1, b="b")]], ['dt', 'num', 'row'])

print(df.getNumPartitions())
Copy

Saída

A ferramenta adiciona esse EWI para que você saiba que o getNumPartitions não é necessário.

df = spark.createDataFrame([('2015-04-08',), ('5',), [Row(a=1, b="b")]], ['dt', 'num', 'row'])
#EWI: SPRKPY1071 => The getNumPartitions are not required in Snowpark. So, you should remove all references.

print(df.getNumPartitions())
Copy

Correção recomendada

Remover todos os usos dessa função.

df = spark.createDataFrame([('2015-04-08',), ('5',), [Row(a=1, b="b")]], ['dt', 'num', 'row'])
Copy

Recomendações adicionais

SPRKPY1082

Mensagem: A função pyspark.sql.readwriter.DataFrameReader.load não é suportada. Uma solução alternativa é usar o método específico do formato do Snowpark DataFrameReader (avro csv, json, orc, parquet). O parâmetro path deve ser um local de estágio.

Categoria: Aviso

Descrição

A função pyspark.sql.readwriter.DataFrameReader.load não é suportada. A solução alternativa é usar os métodos do Snowpark DataFrameReader.

Cenários

A assinatura spark para esse método DataFrameReader.load(path, format, schema, **options) não existe no Snowpark. Portanto, qualquer uso da função load terá um EWI no código de saída.

Cenário 1

Entrada

Abaixo está um exemplo que tenta carregar dados de uma fonte CSV.

path_csv_file = "/path/to/file.csv"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])

my_session.read.load(path_csv_file, "csv").show()
my_session.read.load(path_csv_file, "csv", schema=schemaParam).show()
my_session.read.load(path_csv_file, "csv", schema=schemaParam, lineSep="\r\n", dateFormat="YYYY/MM/DD").show()
Copy

Saída

O SMA adiciona o EWI SPRKPY1082 para que você saiba que essa função não é compatível com o Snowpark, mas há uma solução alternativa.

path_csv_file = "/path/to/file.csv"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.

my_session.read.load(path_csv_file, "csv").show()
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.
my_session.read.load(path_csv_file, "csv", schema=schemaParam).show()
#EWI: The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.
my_session.read.load(path_csv_file, "csv", schema=schemaParam, lineSep="\r\n", dateFormat="YYYY/MM/DD").show()
Copy

Correção recomendada

Como solução alternativa, você pode usar os métodos do Snowpark DataFrameReader.

  • Correção dos parâmetros path e format:

    • Substitua o método load pelo método csv.

    • O primeiro parâmetro path deve estar em um estágio para fazer uma equivalência com o Snowpark.

Abaixo está um exemplo que cria um estágio temporal e coloca o arquivo nele, depois chama o método CSV.

path_csv_file = "/path/to/file.csv"

## Stage creation

temp_stage = f'{Session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
my_session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {temp_stage}').show()
my_session.file.put(f"file:///path/to/file.csv", f"@{temp_stage}")
stage_file_path = f"{temp_stage}file.csv"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])

my_session.read.csv(stage_file_path).show()
Copy
  • Correção do parâmetro schema:

    • O esquema pode ser definido usando a função schema da seguinte forma:

schemaParam = StructType([
        StructField("name", StringType(), True),
        StructField("city", StringType(), True)
    ])

df = my_session.read.schema(schemaParam).csv(temp_stage)
Copy
  • Correção do parâmetro options:

As opções entre o spark e o snowpark não são as mesmas. Nesse caso, lineSep e dateFormat são substituídos por RECORD_DELIMITER e DATE_FORMAT. A seção de Recomendações adicionais tem uma tabela com todas as equivalências.

Abaixo está um exemplo que cria um dicionário com RECORD_DELIMITER e DATE_FORMAT e chama o método options com esse dicionário.

optionsParam = {"RECORD_DELIMITER": "\r\n", "DATE_FORMAT": "YYYY/MM/DD"}
df = my_session.read.options(optionsParam).csv(stage)
Copy

Cenário 2

Entrada

Abaixo está um exemplo que tenta carregar dados de uma fonte JSON.

path_json_file = "/path/to/file.json"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])

my_session.read.load(path_json_file, "json").show()
my_session.read.load(path_json_file, "json", schema=schemaParam).show()
my_session.read.load(path_json_file, "json", schema=schemaParam, dateFormat="YYYY/MM/DD", timestampFormat="YYYY-MM-DD HH24:MI:SS.FF3").show()
Copy

Saída

O SMA adiciona o EWI SPRKPY1082 para que você saiba que essa função não é compatível com o Snowpark, mas há uma solução alternativa.

path_json_file = "/path/to/file.json"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.

my_session.read.load(path_json_file, "json").show()
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.
my_session.read.load(path_json_file, "json", schema=schemaParam).show()
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.
my_session.read.load(path_json_file, "json", schema=schemaParam, dateFormat="YYYY/MM/DD", timestampFormat="YYYY-MM-DD HH24:MI:SS.FF3").show()
Copy

Correção recomendada

Como solução alternativa, você pode usar os métodos do Snowpark DataFrameReader.

  • Correção dos parâmetros path e format:

    • Substitua o método load pelo método json

    • O primeiro parâmetro path deve estar em um estágio para fazer uma equivalência com o Snowpark.

Abaixo está um exemplo que cria um estágio temporal e coloca o arquivo nele, depois chama o método JSON.

path_json_file = "/path/to/file.json"

## Stage creation

temp_stage = f'{Session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
my_session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {temp_stage}').show()
my_session.file.put(f"file:///path/to/file.json", f"@{temp_stage}")
stage_file_path = f"{temp_stage}file.json"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])

my_session.read.json(stage_file_path).show()
Copy
  • Correção do parâmetro schema:

    • O esquema pode ser definido usando a função schema da seguinte forma:

schemaParam = StructType([
        StructField("name", StringType(), True),
        StructField("city", StringType(), True)
    ])

df = my_session.read.schema(schemaParam).json(temp_stage)
Copy
  • Correção do parâmetro options:

As opções entre o Spark e o snowpark não são as mesmas. Nesse caso, dateFormat e timestampFormat são substituídos por DATE_FORMAT e TIMESTAMP_FORMAT. A seção Additional recommendations tem uma tabela com todas as equivalências.

Abaixo está um exemplo que cria um dicionário com DATE_FORMAT e TIMESTAMP_FORMAT e chama o método options com esse dicionário.

optionsParam = {"DATE_FORMAT": "YYYY/MM/DD", "TIMESTAMP_FORMAT": "YYYY-MM-DD HH24:MI:SS.FF3"}
df = Session.read.options(optionsParam).json(stage)
Copy

Cenário 3

Entrada

Abaixo está um exemplo que tenta carregar dados de uma fonte PARQUET.

path_parquet_file = "/path/to/file.parquet"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])

my_session.read.load(path_parquet_file, "parquet").show()
my_session.read.load(path_parquet_file, "parquet", schema=schemaParam).show()
my_session.read.load(path_parquet_file, "parquet", schema=schemaParam, pathGlobFilter="*.parquet").show()
Copy

Saída

O SMA adiciona o EWI SPRKPY1082 para que você saiba que essa função não é compatível com o Snowpark, mas há uma solução alternativa.

path_parquet_file = "/path/to/file.parquet"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.

my_session.read.load(path_parquet_file, "parquet").show()
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.
my_session.read.load(path_parquet_file, "parquet", schema=schemaParam).show()
#EWI: SPRKPY1082 => The pyspark.sql.readwriter.DataFrameReader.load function is not supported. A workaround is to use Snowpark DataFrameReader format specific method instead (avro csv, json, orc, parquet). The path parameter should be a stage location.
my_session.read.load(path_parquet_file, "parquet", schema=schemaParam, pathGlobFilter="*.parquet").show()
Copy

Correção recomendada

Como solução alternativa, você pode usar os métodos do Snowpark DataFrameReader.

  • Correção dos parâmetros path e format:

    • Substitua o método load pelo método parquet

    • O primeiro parâmetro path deve estar em um estágio para fazer uma equivalência com o Snowpark.

Abaixo está um exemplo que cria um estágio temporal e coloca o arquivo nele, depois chama o método PARQUET.

path_parquet_file = "/path/to/file.parquet"

## Stage creation

temp_stage = f'{Session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
my_session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {temp_stage}').show()
my_session.file.put(f"file:///path/to/file.parquet", f"@{temp_stage}")
stage_file_path = f"{temp_stage}file.parquet"

schemaParam = StructType([
        StructField("Name", StringType(), True),
        StructField("Superhero", StringType(), True)
    ])

my_session.read.parquet(stage_file_path).show()
Copy
  • Correção do parâmetro schema:

    • O esquema pode ser definido usando a função schema da seguinte forma:

schemaParam = StructType([
        StructField("name", StringType(), True),
        StructField("city", StringType(), True)
    ])

df = my_session.read.schema(schemaParam).parquet(temp_stage)
Copy
  • Correção do parâmetro options:

As opções entre Spark e snowpark não são as mesmas; nesse caso, pathGlobFilter é substituído por PATTERN, a seção Additional recommendations tem uma tabela com todas as equivalências.

Abaixo está um exemplo que cria um dicionário com PATTERN e chama o método options com esse dicionário.

optionsParam = {"PATTERN": "*.parquet"}
df = Session.read.options(optionsParam).parquet(stage)
Copy

Recomendações adicionais

  • Leve em conta que as opções entre o spark e o snowpark não são as mesmas, mas podem ser mapeadas:

Opções do Spark

Valor possível

Equivalente do Snowpark

Descrição

header

Verdadeiro ou falso

SKIP_HEADER = 1 / SKIP_HEADER = 0

Para usar a primeira linha de um arquivo como nomes de colunas.

delimiter

Qualquer separador de campo de um ou vários caracteres

FIELD_DELIMITER

Para especificar caractere(s) único(s)/múltiplo(s) como separador para cada coluna/campo.

sep

Qualquer separador de campo de caractere único

FIELD_DELIMITER

Para especificar um único caractere como separador para cada coluna/campo.

encoding

UTF-8, UTF-16, etc…

ENCODING

Para decodificar os arquivos CSV pelo tipo de codificação fornecido. A codificação padrão é UTF-8

lineSep

Qualquer separador de linha de caractere único

RECORD_DELIMITER

Para definir o separador de linha que deve ser usado na análise de arquivos.

pathGlobFilter

Padrão de arquivo

PATTERN

Para definir um padrão para ler arquivos somente com nomes de arquivos que correspondam ao padrão.

recursiveFileLookup

Verdadeiro ou falso

N/A

Para examinar recursivamente um diretório para ler arquivos. O valor padrão dessa opção é False.

quote

Caractere único a ser citado

FIELD_OPTIONALLY_ENCLOSED_BY

Para citar campos/colunas que contêm campos em que o delimitador/separador pode fazer parte do valor. Esse caractere Para citar todos os campos quando usado com a opção quoteAll. O valor padrão dessa opção é aspas duplas («).

nullValue

Cadeia de caracteres para substituir null

NULL_IF

Para substituir os valores nulos pela cadeia de caracteres durante a leitura e gravação do dataframe.

dateFormat

Formato de data válido

DATE_FORMAT

Para definir uma cadeia de caracteres que indica um formato de data. O formato padrão é yyyy-MM-dd.

timestampFormat

Formato de carimbo de data/hora válido

TIMESTAMP_FORMAT

Para definir uma cadeia de caracteres que indica um formato de carimbo de data/hora. O formato padrão é yyyy-MM-dd “T’HH:mm:ss.

escape

Qualquer caractere único

ESCAPE

Para definir um único caractere como caractere de escape para substituir o caractere de escape padrão (\).

inferSchema

Verdadeiro ou falso

INFER_SCHEMA

Detecta automaticamente o esquema do arquivo

mergeSchema

Verdadeiro ou falso

N/A

Não é necessário no snowflake, pois isso acontece sempre que o infer_schema determina a estrutura do arquivo parquet

  • Para a opção modifiedBefore / modifiedAfter, você pode obter o mesmo resultado no Snowflake usando as colunas de metadados e, em seguida, adicionando um filtro como: df.filter(METADATA_FILE_LAST_MODIFIED > 'some_date').

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1045

Mensagem: pyspark.sql.functions.map_values tem uma solução alternativa

Categoria: Aviso.

Descrição

Essa função é usada para extrair a lista de valores de uma coluna que contém um mapa/dicionário (chaves/valores).

O problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.map_values, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso do método map_values.

df = spark.createDataFrame(
    [(1, {'Apple': 'Fruit', 'Potato': 'Vegetable'})],
    ("id", "a_map"))

df.select(map_values("a_map")).show()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1045 indicando que uma solução alternativa pode ser implementada.

df = spark.createDataFrame(
    [(1, {'Apple': 'Fruit', 'Potato': 'Vegetable'})],
    ("id", "a_map"))
#EWI: SPRKPY1045 => pyspark.sql.functions.map_values has a workaround, see documentation for more info

df.select(map_values("a_map")).show()
Copy

Correção recomendada

Como solução alternativa, você pode criar um udf para obter os valores de uma coluna. O exemplo a seguir mostra como criar o udf, atribuí-lo a F.map_values e usá-lo.

from snowflake.snowpark import functions as F
from snowflake.snowpark.types import ArrayType, MapType

map_values_udf=None

def map_values(map):
    global map_values_udf
    if not map_values_udf:
        def _map_values(map: dict)->list:
            return list(map.values())
        map_values_udf = F.udf(_map_values,return_type=ArrayType(),input_types=[MapType()],name="map_values",is_permanent=False,replace=True)
    return map_values_udf(map)

F.map_values = map_values

df.select(map_values(colDict))
Copy

Recomendações adicionais

SPRKPY1014

Mensagem: pyspark.sql.functions.asinh tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.asinh, que tem uma solução alternativa.

Cenário

Entrada

Nesse exemplo, o pyspark calcula o asinh para um dataframe usando pyspark.sql.functions.asinh.

from pyspark.sql import SparkSession
from pyspark.sql.functions import asinh
spark = SparkSession.builder.getOrCreate()
data = [['V1', 3.0],
        ['V2', 60.0],
        ['V3', 14.0],
        ['V4', 3.1]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
df_result = df.withColumn("asinh_value", asinh(df["value"]))
Copy

Saída

O SMA retorna o EWI SPRKPY1014 sobre a linha em que o asinh é usado, para que você possa identificar onde corrigir.

from snowflake.snowpark import Session

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['V1', 3.0],
        ['V2', 60.0],
        ['V3', 14.0],
        ['V4', 3.1]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
#EWI: SPRKPY1014 => pyspark.sql.functions.asinh has a workaround, see documentation for more info
df_result = df.withColumn("asinh_value", asinh(df["value"]))
Copy

Correção recomendada

Não há implementação direta do «asinh», mas, em vez disso, pode-se usar «call_function «, usando «asinh» como o primeiro parâmetro e colName como o segundo.

import snowflake.snowpark as snowpark
from snowflake.snowpark import Session
from snowflake.snowpark.functions import call_function, col

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['V1', 3.0],
        ['V2', 60.0],
        ['V3', 14.0],
        ['V4', 3.1]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
df_result = df.select(call_function('asinh', col('value')))
Copy

Recomendações adicionais

SPRKPY1004

Message : A tabela de símbolos não pôde ser carregada.

Category : Erro de análise.

Descrição

Esse problema aparece quando há um erro inesperado no processo de execução da ferramenta. Como a tabela de símbolos não pode ser carregada, a ferramenta não pode iniciar o processo de avaliação ou conversão.

Recomendações adicionais

SPRKPY1055

Mensagem: o valor da chave pyspark.sql.readwriter.DataFrameReader.option não é suportado.

Categoria: Aviso.

Descrição

Esse problema aparece quando o valor da chave pyspark.sql.readwriter.DataFrameReader.option não é suportado pelo SnowFlake.

A ferramenta analisa os parâmetros de chamada de opção e, dependendo do método (CSV ou JSON ou PARQUET), o valor da chave pode ter ou não um equivalente no Snowpark. Se todos os parâmetros tiverem um equivalente, a ferramenta não adicionará o EWI e substituirá o valor da chave pelo seu equivalente; caso contrário, a ferramenta adicionará o EWI.

Lista de equivalências:

  • Equivalências para CSV:

Chaves de opção do Spark

Equivalências do Snowpark

sep

FIELD_DELIMITER

header

PARSE_HEADER

lineSep

RECORD_DELIMITER

pathGlobFilter

PATTERN

quote

FIELD_OPTIONALLY_ENCLOSED_BY

nullValue

NULL_IF

dateFormat

DATE_FORMAT

timestampFormat

TIMESTAMP_FORMAT

inferSchema

INFER_SCHEMA

delimiter

FIELD_DELIMITER

  • Equivalências para JSON:

Chaves de opção do Spark

Equivalências do Snowpark

dateFormat

DATE_FORMAT

timestampFormat

TIMESTAMP_FORMAT

pathGlobFilter

PATTERN

  • Equivalências para PARQUET:

Chaves de opção do Spark

Equivalências do Snowpark

pathGlobFilter

PATTERN

Qualquer outra opção de chave que não esteja em uma das tabelas acima não é compatível ou não tem um equivalente no Snowpark. Se esse for o caso, a ferramenta adiciona o EWI com as informações do parâmetro e o remove da cadeia.

Cenários

Os cenários abaixo se aplicam a CSV, JSON e PARQUET.

Há alguns cenários que dependem do valor da chave usada no método option.

Cenário 1

Entrada

Abaixo está um exemplo de uma chamada option usando uma chave equivalente.

from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

## CSV example:
spark.read.option("header", True).csv(csv_file_path)

## Json example:
spark.read.option("dateFormat", "dd-MM-yyyy").json(json_file_path)

## Parquet example:
spark.read.option("pathGlobFilter", "*.parquet").parquet(parquet_file_path)
Copy

Saída

A ferramenta transforma a chave com o equivalente correto.

from snowflake.snowpark import Session

spark = Session.builder.getOrCreate()

## CSV example:
spark.read.option("PARSE_HEADER", True).csv(csv_file_path)

## Json example:
spark.read.option("DATE_FORMAT", "dd-MM-yyyy").json(json_file_path)

## Parquet example:
spark.read.option("PATTERN", "*.parquet").parquet(parquet_file_path)
Copy

Correção recomendada

Como a ferramenta transforma o valor da chave, não há necessidade de correção.

Cenário 2

Entrada

Abaixo está um exemplo de uma chamada option usando uma chave não equivalente.

from pyspark.sql import SparkSession

spark = SparkSession.builder.getOrCreate()

## CSV example:
spark.read.option("anotherKeyValue", "myVal").csv(csv_file_path)

## Json example:
spark.read.option("anotherKeyValue", "myVal").json(json_file_path)

## Parquet example:
spark.read.option("anotherKeyValue", "myVal").parquet(parquet_file_path)
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1055 indicando que a chave não é compatível e remove a chamada option.

from snowflake.snowpark import Session

spark = Session.builder.getOrCreate()

## CSV example:
#EWI: SPRKPY1055 => pyspark.sql.readwriter.DataFrameReader.option with key value "anotherKeyValue" is not supported.
spark.read.csv(csv_file_path)

## Json example:
#EWI: SPRKPY1055 => pyspark.sql.readwriter.DataFrameReader.option with key value "anotherKeyValue" is not supported.
spark.read.json(json_file_path)

## Parquet example:
#EWI: SPRKPY1055 => pyspark.sql.readwriter.DataFrameReader.option with key value "anotherKeyValue" is not supported.
spark.read.parquet(parquet_file_path)
Copy

Correção recomendada

Recomenda-se que verifique o comportamento após a transformação.

Recomendações adicionais

  • Quando houver parâmetros não equivalentes, é recomendável verificar o comportamento após a transformação.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1061

Mensagem: O Snowpark não é compatível com as funções unix_timestamp

Categoria: Aviso

Descrição

No Snowpark, o primeiro parâmetro é obrigatório; o problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.unix_timestamp sem parâmetros.

Cenário

Entrada

Abaixo, um exemplo que chama o método unix_timestamp sem parâmetros.

data = [["2015-04-08", "10"],["2015-04-10", "15"]]

df = spark.createDataFrame(data, ['dt', 'val'])
df.select(unix_timestamp()).show()
Copy

Saída

A assinatura do Snowpark para essa função unix_timestamp(e: ColumnOrName, fmt: Optional["Column"] = None), como você pode notar, o primeiro parâmetro é obrigatório.

A ferramenta adiciona este EWI SPRKPY1061 para que saiba que a função unix_timestamp sem parâmetros não é compatível com o Snowpark.

data = [["2015-04-08", "10"],["2015-04-10", "15"]]

df = spark.createDataFrame(data, ['dt', 'val'])
#EWI: SPRKPY1061 => Snowpark does not support unix_timestamp functions with no parameters. See documentation for more info.
df.select(unix_timestamp()).show()
Copy

Correção recomendada

Como solução alternativa, você pode adicionar pelo menos o nome ou a coluna da cadeia de caracteres de carimbo de data/hora.

data = [["2015-04-08", "10"],["2015-04-10", "15"]]

df = spark.createDataFrame(data, ["dt", "val"])
df.select(unix_timestamp("dt")).show()
Copy

Recomendações adicionais

SPRKPY1030

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.session.SparkSession.Builder.appName tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.session.SparkSession.Builder.appName, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.session.SparkSession.Builder.appName que gera esse EWI. Neste exemplo, a função appName é usada para definir MyApp como o nome do aplicativo.

session = SparkSession.builder.appName("MyApp").getOrCreate()
Copy

Saída

O SMA adiciona o EWI SPRKPY1030 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

#EWI: SPRKPY1030 => pyspark.sql.session.SparkSession.Builder.appName has a workaround, see documentation for more info
session = Session.builder.appName("MyApp").getOrCreate()
Copy

Correção recomendada

Como solução alternativa, você pode importar o pacote snowpark_extensions, que fornece uma extensão para a função appName.

import snowpark_extensions
session = SessionBuilder.appName("MyApp").getOrCreate()
Copy

Recomendações adicionais

SPRKPY1010

Mensagem: pyspark.sql.dataframe.DataFrame.checkpoint tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.dataframe.DataFrame.checkpoint que tem uma solução alternativa.

Cenário

Entrada

Em PySpark, os pontos de controle são usados para truncar o plano lógico de um dataframe, para evitar o crescimento de um plano lógico.

import tempfile
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
data = [['Q1', 300000],
        ['Q2', 60000],
        ['Q3', 500002],
        ['Q4', 130000]]

columns = ['Quarter', 'Score']
df = spark.createDataFrame(data, columns)
with tempfile.TemporaryDirectory() as d:
    spark.sparkContext.setCheckpointDir("/tmp/bb")
    df.checkpoint(False)
Copy

Saída

O SMA retorna o EWI SPRKPY1010 sobre a linha em que approxQuantile é usado, para que você possa identificar onde corrigir. Observe que isso também marca o diretório setCheckpointDir como sem suporte, mas não é necessário um diretório com ponto de verificação para a correção.

import tempfile
from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 300000],
        ['Q2', 60000],
        ['Q3', 500002],
        ['Q4', 130000]]

columns = ['Quarter', 'Score']
df = spark.createDataFrame(data, columns)
with tempfile.TemporaryDirectory() as d:
    #EWI: SPRKPY1002 => pyspark.context.SparkContext.setCheckpointDir is not supported
    spark.setCheckpointDir("/tmp/bb")
    #EWI: SPRKPY1010 => pyspark.sql.dataframe.DataFrame.checkpoint has a workaround, see documentation for more info
    df.checkpoint(False)
Copy

Correção recomendada

O Snowpark elimina a necessidade de pontos de verificação explícitos: isso ocorre porque o Snowpark trabalha com operações baseadas em SQLque são otimizadas pelo mecanismo de otimização de consultas do Snowflake, eliminando a necessidade de cálculos não correspondidos ou planos lógicos que ficam fora de controle.

No entanto, pode haver cenários em que você precise manter o resultado de um cálculo em um dataframe. Nesses cenários, você pode salvar a materialização dos resultados gravando o dataframe em uma tabela Snowflake ou em uma tabela temporária Snowflake.

  • Com o uso de uma tabela permanente, o resultado computado pode ser acessado a qualquer momento, mesmo após o término da sessão.

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 300000],
        ['Q2', 60000],
        ['Q3', 500002],
        ['Q4', 130000]]

columns = ['Quarter', 'Score']
df = spark.createDataFrame(data, columns)
df.write.save_as_table("my_table", table_type="temporary") # Save the dataframe into Snowflake table "my_table".
df2 = Session.table("my_table") # Now I can access the stored result quering the table "my_table"
Copy
  • Uma solução alternativa, o uso de uma tabela temporária, tem a vantagem de que a tabela é excluída após o término da sessão:

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 300000],
        ['Q2', 60000],
        ['Q3', 500002],
        ['Q4', 130000]]

columns = ['Quarter', 'Score']
df = spark.createDataFrame(data, columns)
df.write.save_as_table("my_temp_table", table_type="temporary") # Save the dataframe into Snowflake table "my_temp_table".
df2 = Session.table("my_temp_table") # Now I can access the stored result quering the table "my_temp_table"
Copy

Recomendações adicionais

SPRKPY1101

Categoria

Erro de análise.

Descrição

Quando a ferramenta reconhece um erro de análise, ela tenta se recuperar dele e continua o processo na próxima linha. Nesses casos, ele mostra o erro e os comentários sobre a linha.

Este exemplo mostra como é tratado um erro de incompatibilidade entre espaços e tabulações.

Código de entrada

def foo():
    x = 5 # Spaces
	y = 6 # Tab

def foo2():
    x=6
    y=7
Copy

Código de saída

def foo():
    x = 5 # Spaces
## EWI: SPRKPY1101 => Unrecognized or invalid CODE STATEMENT @(3, 2). Last valid token was '5' @(2, 9), failed token 'y' @(3, 2)
## y = 6 # Tab

def foo2():
    x=6
    y=7
Copy

Recomendações

  • Tente corrigir a linha comentada.

  • Para obter mais suporte, envie-nos um e-mail para sma-support@snowflake.com. Se tiver um contrato de suporte com a Snowflake, entre em contato com seu engenheiro de vendas, que poderá direcionar suas necessidades de suporte.

SPRKPY1041

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 2.9.0

Mensagem: pyspark.sql.functions.explode_outer tem uma solução alternativa

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.explode_outer, que tem uma solução alternativa.

Cenário

Entrada

O exemplo mostra o uso do método explode_outer em uma chamada de seleção.

df = spark.createDataFrame(
    [(1, ["foo", "bar"], {"x": 1.0}),
     (2, [], {}),
     (3, None, None)],
    ("id", "an_array", "a_map")
)

df.select("id", "an_array", explode_outer("a_map")).show()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1041 indicando que uma solução alternativa pode ser implementada.

df = spark.createDataFrame(
    [(1, ["foo", "bar"], {"x": 1.0}),
     (2, [], {}),
     (3, None, None)],
    ("id", "an_array", "a_map")
)

#EWI: SPRKPY1041 => pyspark.sql.functions.explode_outer has a workaround, see documentation for more info
df.select("id", "an_array", explode_outer("a_map")).show()
Copy

Correção recomendada

Como solução alternativa, você senhor pode importar o pacote snowpark_extensions, que contém um auxiliar para a função explode_outer.

import snowpark_extensions

df = spark.createDataFrame(
    [(1, ["foo", "bar"], {"x": 1.0}),
     (2, [], {}),
     (3, None, None)],
    ("id", "an_array", "a_map")
)

df.select("id", "an_array", explode_outer("a_map")).show()
Copy

Recomendações adicionais

SPRKPY1075

Categoria

Aviso.

Descrição

O parse_json não aplica validação de esquema; se precisar filtrar/validar com base no esquema, talvez seja necessário introduzir alguma lógica.

Exemplo

Entrada

df.select(from_json(df.value, Schema))
df.select(from_json(schema=Schema, col=df.value))
df.select(from_json(df.value, Schema, option))
Copy

Saída

#EWI: SPRKPY1075 => The parse_json does not apply schema validation, if you need to filter/validate based on schema you might need to introduce some logic.
df.select(parse_json(df.value))
#EWI: SPRKPY1075 => The parse_json does not apply schema validation, if you need to filter/validate based on schema you might need to introduce some logic.
df.select(parse_json(df.value))
#EWI: SPRKPY1075 => The parse_json does not apply schema validation, if you need to filter/validate based on schema you might need to introduce some logic.
df.select(parse_json(df.value))
Copy

Para a função from_json, o esquema não é realmente passado para inferência, mas é usado para validação. Veja estes exemplos:

data = [
    ('{"name": "John", "age": 30, "city": "New York"}',),
    ('{"name": "Jane", "age": "25", "city": "San Francisco"}',)
]

df = spark.createDataFrame(data, ["json_str"])
Copy

Exemplo 1: Aplicar tipos de dados e alterar nomes de colunas:

## Parse JSON column with schema
parsed_df = df.withColumn("parsed_json", from_json(col("json_str"), schema))

parsed_df.show(truncate=False)

## +------------------------------------------------------+---------------------------+
## |json_str                                              |parsed_json                |
## +------------------------------------------------------+---------------------------+
## |{"name": "John", "age": 30, "city": "New York"}       |{John, 30, New York}       |
## |{"name": "Jane", "age": "25", "city": "San Francisco"}|{Jane, null, San Francisco}|
## +------------------------------------------------------+---------------------------+
## notice that values outside of the schema were dropped and columns not matched are returned as null
Copy

Exemplo 2: Selecionar colunas específicas:

## Define a schema with only the columns we want to use
partial_schema = StructType([
    StructField("name", StringType(), True),
    StructField("city", StringType(), True)
])

## Parse JSON column with partial schema
partial_df = df.withColumn("parsed_json", from_json(col("json_str"), partial_schema))

partial_df.show(truncate=False)

## +------------------------------------------------------+---------------------+
## |json_str                                              |parsed_json          |
## +------------------------------------------------------+---------------------+
## |{"name": "John", "age": 30, "city": "New York"}       |{John, New York}     |
## |{"name": "Jane", "age": "25", "city": "San Francisco"}|{Jane, San Francisco}|
## +------------------------------------------------------+---------------------+
## there is also an automatic filtering
Copy

Recomendações

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com. Se tiver um contrato de suporte com a Snowflake, entre em contato com seu engenheiro de vendas para que ele possa direcionar suas necessidades de suporte.

  • Ferramentas úteis PEP-8 e Reindent.

SPRKPY1024

Mensagem: pyspark.sql.functions.log2 tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.log2, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.log2 que gera esse EWI. Neste exemplo, a função log2 é usada para calcular o logaritmo de base 2 da coluna value.

df = spark.createDataFrame([(1,), (2,), (4,), (8,), (16,)], ["value"])
df_with_log2 = df.withColumn("log2_value", log2(df["value"]))
Copy

Saída

O SMA adiciona o EWI SPRKPY1024 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([(1,), (2,), (4,), (8,), (16,)], ["value"])
#EWI: SPRKPY1024 => pyspark.sql.functions.log2 has a workaround, see documentation for more info
df_with_log2 = df.withColumn("log2_value", log2(df["value"]))
Copy

Correção recomendada

Como solução alternativa, você pode usar a função snowflake.snowpark.functions.log passando o valor literal 2 como base.

df = session.createDataFrame([(1,), (2,), (4,), (8,), (16,)], ["value"])
df_with_log2 = df.withColumn("log2_value", log(2, df["value"]))
Copy

Recomendações adicionais

SPRKPY1086

Mensagem: pyspark.ml.linalg.VectorUDT não é compatível.

Categoria: Aviso

Descrição

O pyspark.ml.linalg.VectorUDT não é compatível.

Cenário

Código de entrada

VectorUDT é um tipo de dados para representar colunas de vetores em um DataFrame.

data = [
        (1, Vectors.dense([10.0, 20.0])),
        (2, Vectors.dense([25.0, 30.0])),
        (3, Vectors.dense([50.0, 60.0]))
    ]

schema = StructType([
        StructField("Id", IntegerType(), True),
        StructField("VectorCol", VectorUDT(), True),
    ])

df = SparkSession.createDataFrame(data, schema=schema)
Copy

Código de saída

A ferramenta adiciona esse EWI SPRKPY1086 no código de saída para que você saiba que essa função não é compatível com o Snowpark.

data = [
        (1, Vectors.dense([10.0, 20.0])),
        (2, Vectors.dense([25.0, 30.0])),
        (3, Vectors.dense([50.0, 60.0]))
    ]

#EWI: SPRKPY1086 => The pyspark.ml.linalg.VectorUDT function is not supported.
schema = StructType([
        StructField("Id", IntegerType(), True),
        StructField("VectorCol", VectorUDT(), True),
    ])

df = spark.createDataFrame(data, schema=schema)
Copy

Correção recomendada

O pyspark.ml.linalg.VectorUDT não tem uma correção recomendada.

Recomendações adicionais

SPRKPY1034

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.functions.desc tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.desc, que tem uma solução alternativa.

Cenários

A função pyspark.sql.functions.desc recebe como parâmetro um objeto de coluna ou o nome da coluna como uma cadeia de caracteres. Ambos os cenários não são compatíveis com o Snowpark, portanto, este EWI é gerado.

Cenário 1

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.desc que recebe um objeto de coluna como parâmetro.

df.orderBy(desc(col))
Copy

Saída

O SMA adiciona o EWI SPRKPY1034 ao código de saída para que você saiba que a função desc com um parâmetro de objeto de coluna não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

#EWI: SPRKPY1034 => pyspark.sql.functions.desc has a workaround, see documentation for more info
df.orderBy(desc(col))
Copy

Correção recomendada

Como solução alternativa, o senhor pode chamar a função snowflake.snowpark.Column.desc a partir do parâmetro da coluna.

df.orderBy(col.desc())
Copy
Cenário 2

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.desc que usa o nome da coluna como parâmetro.

df.orderBy(desc("colName"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1034 ao código de saída para que você saiba que a função desc com um parâmetro de nome de coluna não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

#EWI: SPRKPY1034 => pyspark.sql.functions.desc has a workaround, see documentation for more info
df.orderBy(desc("colName"))
Copy

Correção recomendada

Como solução alternativa, você pode converter o parâmetro string em um objeto de coluna usando a função snowflake.snowpark.functions.col e, em seguida, chamar a função snowflake.snowpark.Column.desc.

df.orderBy(col("colName").desc())
Copy

Recomendações adicionais

SPRKPY1065

Mensagem: O pyspark.context.SparkContext.broadcast não se aplica, pois o snowflake usa o mecanismo data-clustering para computar os dados.

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso do elemento pyspark.context.SparkContext.broadcast, que não é necessário devido ao uso de data-clustering do Snowflake.

Código de entrada

Neste exemplo, é criada uma variável de transmissão. Essas variáveis permitem que os dados sejam compartilhados de forma mais eficiente por todos os nós.

sc = SparkContext(conf=conf_spark)

mapping = {1: 10001, 2: 10002}

bc = sc.broadcast(mapping)
Copy

Código de saída

O SMA adiciona uma mensagem EWI indicando que a transmissão não é necessária.

sc = conf_spark

mapping = {1: 10001, 2: 10002}
#EWI: SPRKPY1065 => The element does not apply since snowflake use data-clustering mechanism to compute the data.

bc = sc.broadcast(mapping)
Copy

Correção recomendada

Remova todos os usos de pyspark.context.SparkContext.broadcast.

sc = conf_spark

mapping = {1: 10001, 2: 10002}
Copy

Recomendações adicionais

SPRKPY1051

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 2.4.0

Mensagem: pyspark.sql.session.SparkSession.Builder.master tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.session.SparkSession.Builder.master, que tem uma solução alternativa.

Cenário

Entrada

Abaixo está um exemplo do uso do método builder.master para definir o Spark Master URL para se conectar ao local usando 1 núcleo.

spark = SparkSession.builder.master("local[1]")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1051 indicando que uma solução alternativa pode ser implementada.

#EWI: SPRKPY1051 => pyspark.sql.session.SparkSession.Builder.master has a workaround, see documentation for more info
spark = Session.builder.master("local[1]")
Copy

Correção recomendada

pyspark.sql.session.SparkSession.Builder.master é usado para configurar um Spark Cluster. O Snowpark não usa Spark Clusters, então você pode remover ou comentar o código.

## spark = Session.builder.master("local[1]")
Copy

Recomendações adicionais

SPRKPY1000

Mensagem: A versão do núcleo de projeto spark-core de origem é xx.xx:xx.x.x, a versão do spark-core suportada pelo snowpark é 2.12:3.1.2, portanto, pode haver diferenças funcionais entre os mapeamentos existentes.

Categoria: Aviso.

Descrição

Esse problema aparece quando a versão do Pyspark do seu código-fonte não é compatível. Isso significa que pode haver diferenças funcionais entre os mapeamentos existentes.

Recomendações adicionais

  • A versão do pyspark verificada pelo SMA para compatibilidade com o Snowpark é de 2.12 a 3.1.2. Se estiver usando uma versão fora desse intervalo, a ferramenta poderá produzir resultados inconsistentes. Você pode alterar a versão do código-fonte que está verificando.

  • Para obter mais suporte, você pode enviar um e-mail para sma-support@snowflake.com ou publicar um problema no SMA.

SPRKPY1081

Esse código de problema foi depreciado desde o Spark Conversion Core 4.12.0

Mensagem: pyspark.sql.readwriter.DataFrameWriter.partitionBy tem uma solução alternativa.

Categoria: Aviso

Descrição

Não há suporte para a função Pyspark.sql.readwriter.DataFrameWriter.partitionBy. A solução alternativa é usar o copy_into_location do Snowpark. Consulte a documentação para obter mais informações.

Cenário

Entrada

Esse código criará um diretório separado para cada valor exclusivo na coluna FIRST_NAME. Os dados são os mesmos, mas serão armazenados em diretórios diferentes com base na coluna.

df = session.createDataFrame([["John", "Berry"], ["Rick", "Berry"], ["Anthony", "Davis"]], schema = ["FIRST_NAME", "LAST_NAME"])
df.write.partitionBy("FIRST_NAME").csv("/home/data")
Copy

Esse código criará um diretório separado para cada valor exclusivo na coluna FIRST_NAME. Os dados são os mesmos, mas serão armazenados em diretórios diferentes com base na coluna.

Código de saída

df = session.createDataFrame([["John", "Berry"], ["Rick", "Berry"], ["Anthony", "Davis"]], schema = ["FIRST_NAME", "LAST_NAME"])
#EWI: SPRKPY1081 => The partitionBy function is not supported, but you can instead use copy_into_location as workaround. See the documentation for more info.
df.write.partitionBy("FIRST_NAME").csv("/home/data", format_type_options = dict(compression = "None"))
Copy

Correção recomendada

No Snowpark, copy_into_location tem um parâmetro partition_by que você pode usar em vez da função partitionBy, mas isso exigirá alguns ajustes manuais, conforme mostrado no exemplo a seguir:

Código do Spark:

df = session.createDataFrame([["John", "Berry"], ["Rick", "Berry"], ["Anthony", "Davis"]], schema = ["FIRST_NAME", "LAST_NAME"])
df.write.partitionBy("FIRST_NAME").csv("/home/data")
Copy

O código do Snowpark foi ajustado manualmente:

df = session.createDataFrame([["John", "Berry"], ["Rick", "Berry"], ["Anthony", "Davis"]], schema = ["FIRST_NAME", "LAST_NAME"])
df.write.copy_into_location(location=temp_stage, partition_by=col("FIRST_NAME"), file_format_type="csv", format_type_options={"COMPRESSION": "NONE"}, header=True)
Copy

copy_into_location tem os seguintes parâmetros

  • location: O local do Snowpark só aceita locais de nuvem que usam um estágio do snowflake.

  • partition_by: Pode ser um nome de coluna ou uma expressão SQL, portanto, você precisará convertê-la em uma coluna ou em uma expressão SQL, usando col ou sql_expr.

Recomendações adicionais

SPRKPY1072

Mensagem: O uso do StorageLevel não é obrigatório no Snowpark.

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta encontra o uso da classe StorageLevel que funciona como «sinalizadores» para definir o nível de armazenamento. Como o Snowflake controla o armazenamento, o uso dessa função não é necessário.

Recomendações adicionais

SPRKPY1023

Mensagem: pyspark.sql.functions.log1p tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.log1p, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.log1p que gera esse EWI. Neste exemplo, a função log1p é usada para calcular o logaritmo natural da coluna value.

df = spark.createDataFrame([(0,), (1,), (10,), (100,)], ["value"])
df_with_log1p = df.withColumn("log1p_value", log1p(df["value"]))
Copy

Saída

O SMA adiciona o EWI SPRKPY1023 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([(0,), (1,), (10,), (100,)], ["value"])
#EWI: SPRKPY1023 => pyspark.sql.functions.log1p has a workaround, see documentation for more info
df_with_log1p = df.withColumn("log1p_value", log1p(df["value"]))
Copy

Correção recomendada

Como solução alternativa, você pode usar a função call_function passando a cadeia de caracteres ln como primeiro argumento e adicionando 1 ao segundo argumento.

df = spark.createDataFrame([(0,), (1,), (10,), (100,)], ["value"])
df_with_log1p = df.withColumn("log1p_value", call_function("ln", lit(1) + df["value"]))
Copy

Recomendações adicionais

SPRKPY1017

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 4.8.0

pyspark.sql.functions.date_add tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.date_add, que tem uma solução alternativa.

Cenário

Entrada

Neste exemplo, usamos date_add para calcular a data 5 dias após a data atual para o dataframe df.

col = df.select(date_add(df.colName, 5))
Copy

Saída

SMA retorna o EWI SPRKPY1017 sobre a linha em que date_add é usado, para que você possa identificar onde corrigir.

#EWI: SPRKPY1017 => pyspark.sql.functions.date_add has a workaround, see documentation for more info
col = df.select(date_add(df.colName, 5))
Copy

Correção recomendada

Importe snowflake.snowpark.functions, que contém uma implementação para a função date_add (e o alias dateAdd).

from snowflake.snowpark.functions import date_add

col = df.select(date_add(df.dt, 1))
Copy

Recomendações adicionais

SPRKPY1046

Aviso

Esse código de problema foi descontinuado desde o Spark Conversion Core Version 2.1.22

Mensagem: pyspark.sql.functions.monotonically_increasing_id tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.monotonically_increasing_id, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso do método monotonically_increasing_id.

from pyspark.sql import functions as F

spark.range(0, 10, 1, 2).select(F.monotonically_increasing_id()).show()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1046 indicando que uma solução alternativa pode ser implementada.

from pyspark.sql import functions as F
#EWI: SPRKPY1046 => pyspark.sql.functions.monotonically_increasing_id has a workaround, see documentation for more info
spark.range(0, 10, 1, 2).select(F.monotonically_increasing_id()).show()
Copy

Correção recomendada

Atualize a versão da ferramenta.

Recomendações adicionais

SPRKPY1056

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.readwriter.DataFrameReader.option argument _ <argument_name> _ não é um literal e não pode ser avaliado

Categoria: Aviso

Descrição

Esse problema aparece quando a chave ou o valor do argumento da função pyspark.sql.readwriter.DataFrameReader.option não é um valor literal (por exemplo, uma variável). O SMA faz uma análise estática do seu código-fonte e, portanto, não é possível avaliar o conteúdo do argumento.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.readwriter.DataFrameReader.option que gera esse EWI.

my_value = ...
my_option = ...

df1 = spark.read.option("dateFormat", my_value).format("csv").load('filename.csv')
df2 = spark.read.option(my_option, "false").format("csv").load('filename.csv')
Copy

Saída

O SMA adiciona o EWI SPRKPY1056 ao código de saída para que você saiba que o argumento dessa função não é um valor literal e, portanto, não pode ser avaliado pelo SMA.

my_value = ...
my_option = ...

#EWI: SPRKPY1056 => pyspark.sql.readwriter.DataFrameReader.option argument "dateFormat" is not a literal and can't be evaluated
df1 = spark.read.option("dateFormat", my_value).format("csv").load('filename.csv')
#EWI: SPRKPY1056 => pyspark.sql.readwriter.DataFrameReader.option argument key is not a literal and can't be evaluated
df2 = spark.read.option(my_option, "false").format("csv").load('filename.csv')
Copy

Correção recomendada

Mesmo que o SMA não tenha conseguido avaliar o argumento, isso não significa que ele não seja apoiado pelo Snowpark. Certifique-se de que o valor do argumento seja válido e equivalente no Snowpark, verificando a documentação.

Recomendações adicionais

SPRKPY1007

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 4.8.0

Message : pyspark.sql.context.SQLContext não é necessário

Category : Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.sql.context.SQLContext, que não é necessário.

Cenário

Entrada

Aqui temos um exemplo com diferentes sobrecargas de SparkContext.

from pyspark import SQLContext

my_sc1 = SQLContext(myMaster, myAppName, mySparkHome, myPyFiles, myEnvironment, myBatctSize, mySerializer, my_conf1)
my_sc2 = SQLContext(conf=my_conf2)
my_sc3 = SQLContext()
Copy

Saída

O código de saída comentou a linha do pyspark.SQLContext, e substitui os cenários por uma referência a uma configuração. Observe que as variáveis my_sc1 e my_sc2 que contêm propriedades do Spark podem não ser necessárias ou terão de ser adaptadas para corrigir o código.

#EWI: SPRKPY1007 => pyspark.sql.context.SQLContext is not required
#from pyspark import SQLContext
pass

#EWI: SPRKPY1007 => pyspark.sql.context.SQLContext is not required
sql_context1 = my_sc1
#EWI: SPRKPY1007 => pyspark.sql.context.SQLContext is not required
sql_context2 = my_sc2
Copy

Recomendações adicionais

  • Esse é um parâmetro desnecessário e é removido com um comentário de aviso inserido no código-fonte. Não deve haver nenhuma ação por parte do usuário.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1033

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.functions.asc tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.asc, que tem uma solução alternativa.

Cenários

A função pyspark.sql.functions.asc recebe como parâmetro um objeto de coluna ou o nome da coluna como uma cadeia de caracteres. Ambos os cenários não são compatíveis com o Snowpark, portanto, este EWI é gerado.

Cenário 1

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.asc que recebe um objeto de coluna como parâmetro.

df.orderBy(asc(col))
Copy

Saída

O SMA adiciona o EWI SPRKPY1033 ao código de saída para que você saiba que a função asc com um parâmetro de objeto de coluna não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

#EWI: SPRKPY1033 => pyspark.sql.functions.asc has a workaround, see documentation for more info
df.orderBy(asc(col))
Copy

Correção recomendada

Como solução alternativa, você pode chamar a função snowflake.snowpark.Column.asc a partir do parâmetro column.

df.orderBy(col.asc())
Copy
Cenário 2

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.asc que recebe o nome da coluna como parâmetro.

df.orderBy(asc("colName"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1033 ao código de saída para que você saiba que a função asc com um parâmetro de nome de coluna não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

#EWI: SPRKPY1033 => pyspark.sql.functions.asc has a workaround, see documentation for more info
df.orderBy(asc("colName"))
Copy

Correção recomendada

Como solução alternativa, você pode converter o parâmetro string em um objeto de coluna usando a função snowflake.snowpark.functions.col e, em seguida, chamar a função snowflake.snowpark.Column.asc.

df.orderBy(col("colName").asc())
Copy

Recomendações adicionais

SPRKPY1062

Mensagem: O Snowpark não é compatível com GroupedData.pivot sem o parâmetro «values».

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.group.GroupedData.pivot sem o parâmetro «values» (a lista de valores sobre os quais pivotar).

No momento, a função de pivô do Snowpark Python exige que você especifique explicitamente a lista de valores distintos sobre os quais fazer o pivô.

Cenários

Cenário 1

Entrada

O SMA detecta uma expressão que corresponde ao padrão dataFrame.groupBy("columnX").pivot("columnY") e o pivô não tem o parâmetro values.

df.groupBy("date").pivot("category").sum("amount")
Copy

Saída

O SMA adiciona uma mensagem EWI indicando que não há suporte para a função de pivô sem o parâmetro «values».

Além disso, ele adicionará como segundo parâmetro da função de pivô uma compreensão de lista que calcula a lista de valores que serão convertidos em colunas. Lembre-se de que essa operação não é eficiente para grandes conjuntos de dados, e é aconselhável indicar os valores explicitamente.

#EWI: SPRKPY1062 => pyspark.sql.group.GroupedData.pivot without parameter 'values' is not supported. See documentation for more info.
df.groupBy("date").pivot("category", [v[0] for v in df.select("category").distinct().limit(10000).collect()]]).sum("amount")
Copy

Correção recomendada

Para esse cenário, o SMA adiciona um segundo parâmetro da função de pivô, uma compreensão de lista que calcula a lista de valores que serão convertidos em colunas, mas você pode usar uma lista de valores distintos para pivotar, como segue:

df = spark.createDataFrame([
      Row(category="Client_ID", date=2012, amount=10000),
      Row(category="Client_name",   date=2012, amount=20000)
  ])

df.groupBy("date").pivot("category", ["dotNET", "Java"]).sum("amount")
Copy
Cenário 2

Entrada

O SMA não conseguiu detectar uma expressão que corresponda ao padrão dataFrame.groupBy("columnX").pivot("columnY") e o pivô não tem o parâmetro values.

df1.union(df2).groupBy("date").pivot("category").sum("amount")
Copy

Saída

O SMA adiciona uma mensagem EWI indicando que não há suporte para a função de pivô sem o parâmetro «values».

#EWI: SPRKPY1062 => pyspark.sql.group.GroupedData.pivot without parameter 'values' is not supported. See documentation for more info.
df1.union(df2).groupBy("date").pivot("category").sum("amount")
Copy

Correção recomendada

Adicione uma lista de valores distintos para fazer o pivô, como segue:

df = spark.createDataFrame([
      Row(course="dotNET", year=2012, earnings=10000),
      Row(course="Java",   year=2012, earnings=20000)
  ])

df.groupBy("year").pivot("course", ["dotNET", "Java"]).sum("earnings").show()
Copy

Recomendações adicionais

  • O cálculo da lista de valores distintos para pivotar não é uma operação eficiente em grandes conjuntos de dados e pode se tornar uma chamada de bloqueio. Considere a possibilidade de indicar explicitamente a lista de valores distintos para dinamizar.

  • Se não quiser especificar explicitamente a lista de valores distintos para pivotar (o que não é aconselhável), você pode adicionar o seguinte código como o segundo argumento da função pivot para inferir os valores em tempo de execução*

[v[0] for v in <df>.select(<column>).distinct().limit(<count>).collect()]]
Copy

*_ Substitua _ <df> pelo correspondente DataFrame, pela coluna a ser dinamizada e pelo número de linhas a serem selecionadas.

SPRKPY1042

Mensagem: pyspark.sql.functions.posexplode tem uma solução alternativa

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.posexplode, que tem uma solução alternativa.

Cenários

Há alguns cenários com os quais esse método pode lidar, dependendo do tipo de coluna que é passada como parâmetro: pode ser uma lista de valores ou um mapa/diretório (chaves/valores).

Cenário 1

Entrada

Veja abaixo um exemplo de uso do posexplode passando como parâmetro de uma lista de valores.

df = spark.createDataFrame(
    [Row(a=1,
         intlist=[1, 2, 3])])

df.select(posexplode(df.intlist)).collect()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1042 indicando que uma solução alternativa pode ser implementada.

df = spark.createDataFrame(
    [Row(a=1,
         intlist=[100, 200, 300])])
#EWI: SPRKPY1042 => pyspark.sql.functions.posexplode has a workaround, see documentation for more info

df.select(posexplode(df.intlist)).show()
Copy

Correção recomendada

Para ter o mesmo comportamento, use o método functions.flatten, elimine as colunas extras e renomeie os nomes das colunas de índice e valor.

df = spark.createDataFrame(
  [Row(a=1,
       intlist=[1, 2, 3])])

df.select(
    flatten(df.intlist))\
    .drop("DATA", "SEQ", "KEY", "PATH", "THIS")\
    .rename({"INDEX": "pos", "VALUE": "col"}).show()
Copy
Cenário 2

Entrada

Abaixo está outro exemplo de uso do posexplode passando como parâmetro um mapa/dicionário (chaves/valores)

df = spark.createDataFrame([
    [1, [1, 2, 3], {"Ashi Garami": "Single Leg X"}, "Kimura"],
    [2, [11, 22], {"Sankaku": "Triangle"}, "Coffee"]
],
schema=["idx", "lists", "maps", "strs"])

df.select(posexplode(df.maps)).show()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1042 indicando que uma solução alternativa pode ser implementada.

df = spark.createDataFrame([
    [1, [1, 2, 3], {"Ashi Garami": "Single Leg X"}, "Kimura"],
    [2, [11, 22], {"Sankaku": "Triangle"}, "Coffee"]
],
schema=["idx", "lists", "maps", "strs"])
#EWI: SPRKPY1042 => pyspark.sql.functions.posexplode has a workaround, see documentation for more info

df.select(posexplode(df.maps)).show()
Copy

Correção recomendada

Como solução alternativa, você pode usar functions.row_number para obter a posição e functions.explode com o nome do campo para obter o valor da chave/valor para dicionários.

df = spark.createDataFrame([
    [10, [1, 2, 3], {"Ashi Garami": "Single Leg X"}, "Kimura"],
    [11, [11, 22], {"Sankaku": "Triangle"}, "Coffee"]
],
    schema=["idx", "lists", "maps", "strs"])

window = Window.orderBy(col("idx").asc())

df.select(
    row_number().over(window).alias("pos"),
    explode(df.maps).alias("key", "value")).show()
Copy

Observação: usar row_number não é totalmente equivalente, pois começa com 1 (não zero como o método spark)

Recomendações adicionais

SPRKPY1013

Mensagem: pyspark.sql.functions.acosh tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.acosh, que tem uma solução alternativa.

Cenário

Entrada

Neste exemplo, o pyspark calcula o acosh para um dataframe usando pyspark.sql.functions.acosh

from pyspark.sql import SparkSession
from pyspark.sql.functions import acosh
spark = SparkSession.builder.getOrCreate()
data = [['V1', 30],
        ['V2', 60],
        ['V3', 50],
        ['V4', 13]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
df_with_acosh = df.withColumn("acosh_value", acosh(df["value"]))
Copy

Saída

O SMA retorna o EWI SPRKPY1013 sobre a linha em que acosh é usado, para que você possa identificar onde corrigir.

from snowflake.snowpark import Session

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['V1', 30],
        ['V2', 60],
        ['V3', 50],
        ['V4', 13]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
#EWI: SPRKPY1013 => pyspark.sql.functions.acosh has a workaround, see documentation for more info
df_with_acosh = df.withColumn("acosh_value", acosh(df["value"]))
Copy

Correção recomendada

Não há implementação direta de «acosh», mas, em vez disso, pode-se usar «call_function «, usando «acosh» como o primeiro parâmetro e colName como o segundo.

import snowflake.snowpark as snowpark
from snowflake.snowpark import Session
from snowflake.snowpark.functions import call_function, col

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['V1', 30],
        ['V2', 60],
        ['V3', 50],
        ['V4', 13]]

columns = ['Paremeter', 'value']
df = spark.createDataFrame(data, columns)
df_with_acosh = df.select(call_function('ACOSH', col('value')))
Copy

Recomendações adicionais

SPRKPY1085

Mensagem: pyspark.ml.feature.VectorAssembler não é compatível.

Categoria: Aviso

Descrição

O recurso pyspark.ml.feature.VectorAssembler não é compatível.

Cenário

Código de entrada

VectorAssembler é usado para combinar várias colunas em um único vetor.

data = [
        (1, 10.0, 20.0),
        (2, 25.0, 30.0),
        (3, 50.0, 60.0)
    ]

df = SparkSession.createDataFrame(data, schema=["Id", "col1", "col2"])
vector = VectorAssembler(inputCols=["col1", "col2"], output="cols")
Copy

Código de saída

A ferramenta adiciona esse EWI SPRKPY1085 no código de saída para que você saiba que essa classe não é compatível com o Snowpark.

data = [
        (1, 10.0, 20.0),
        (2, 25.0, 30.0),
        (3, 50.0, 60.0)
    ]

df = spark.createDataFrame(data, schema=["Id", "col1", "col2"])
#EWI: SPRKPY1085 => The pyspark.ml.feature.VectorAssembler function is not supported.

vector = VectorAssembler(inputCols=["col1", "col2"], output="cols")
Copy

Correção recomendada

O pyspark.ml.feature.VectorAssembler não tem uma correção recomendada.

Recomendações adicionais

SPRKPY1027

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core 4.5.2

Mensagem: pyspark.sql.readwriter.DataFrameReader.json tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.readwriter.DataFrameReader.json, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.readwriter.DataFrameReader.json que gera este EWI. Neste exemplo, a função json é usada para ler vários arquivos . json com um determinado esquema e usa algumas opções extras, como primitiveAsString e dateFormat para ajustar o comportamento da leitura dos arquivos.

file_paths = [
  "path/to/your/file1.json",
  "path/to/your/file2.json",
  "path/to/your/file3.json",
]

df = session.read.json(
  file_paths,
  schema=my_schema,
  primitiveAsString=True,
  dateFormat="2023-06-20"
)
Copy

Saída

O SMA adiciona o EWI SPRKPY1027 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

file_paths = [
  "path/to/your/file1.json",
  "path/to/your/file2.json",
  "path/to/your/file3.json",
]

#EWI: SPRKPY1027 => pyspark.sql.readwriter.DataFrameReader.json has a workaround, see documentation for more info
df = session.read.json(
  file_paths,
  schema=my_schema,
  primitiveAsString=True,
  dateFormat="2023-06-20"
)
Copy

Correção recomendada

Nesta seção, explicamos como configurar o parâmetro path, o parâmetro schema e algumas opções para fazê-los funcionar no Snowpark.

1. parâmetro path

O Snowpark exige que o parâmetro path seja um local de estágio, portanto, como solução alternativa, você pode criar um estágio temporário e adicionar cada arquivo .json a esse estágio usando o prefixo file://.

2. parâmetro schema

O Snowpark não permite definir schema como um parâmetro da função json. Como solução alternativa, você pode usar a função snowflake.snowpark.DataFrameReader.schema.

3. parâmetros de options

O Snowpark não permite definir opções extras como parâmetros da função json. Como solução alternativa, para muitos deles, você pode usar a função snowflake.snowpark.DataFrameReader.option para especificar esses parâmetros como opções do DataFrameReader.

Nota

As seguintes opções não são suportadas pelo Snowpark:

  • allowBackslashEscapingAnyCharacter

  • allowComments

  • allowNonNumericNumbers

  • allowNumericLeadingZero

  • allowSingleQuotes

  • allowUnquotedControlChars

  • allowUnquotedFieldNames

  • columnNameOfCorruptRecord

  • dropFiledIfAllNull

  • encoding

  • ignoreNullFields

  • lineSep

  • locale

  • mode

  • multiline

  • prefereDecimal

  • primitiveAsString

  • samplingRatio

  • timestampNTZFormat

  • timeZone

Abaixo está o exemplo completo de como o código de entrada deve ficar depois de aplicar as sugestões mencionadas acima para fazê-lo funcionar no Snowpark:

stage = f'{session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {stage}')

session.file.put(f"file:///path/to/your/file1.json", f"@{stage}")
session.file.put(f"file:///path/to/your/file2.json", f"@{stage}")
session.file.put(f"file:///path/to/your/file3.json", f"@{stage}")

df = session.read.schema(my_schema).option("dateFormat", "2023-06-20").json(stage)
Copy

Recomendações adicionais

SPRKPY1076

Mensagem: Os parâmetros nos métodos pyspark.sql.readwriter.DataFrameReader não são suportados. Isso se aplica aos métodos CSV, JSON e PARQUET.

Categoria: Aviso.

Descrição

Para os métodos CSV, JSON e PARQUET no objeto pyspark.sql.readwriter.DataFrameReader, a ferramenta analisará os parâmetros e adicionará uma transformação de acordo com cada caso:

  • Todos os parâmetros correspondem ao seu nome equivalente no Snowpark: nesse caso, a ferramenta transformará o parâmetro em uma chamada .option(). Nesse caso, o parâmetro não adicionará esse EWI.

  • Alguns parâmetros não correspondem ao equivalente no Snowpark: nesse caso, a ferramenta adicionará esse EWI com as informações do parâmetro e o removerá da chamada do método.

Lista de equivalências:

  • Equivalências para CSV:

Chaves do Spark

Equivalências do Snowpark

sep

FIELD_DELIMITER

header

PARSE_HEADER

lineSep

RECORD_DELIMITER

pathGlobFilter

PATTERN

quote

FIELD_OPTIONALLY_ENCLOSED_BY

nullValue

NULL_IF

dateFormat

DATE_FORMAT

timestampFormat

TIMESTAMP_FORMAT

inferSchema

INFER_SCHEMA

delimiter

FIELD_DELIMITER

  • Equivalências para JSON:

Chaves do Spark

Equivalências do Snowpark

dateFormat

DATE_FORMAT

timestampFormat

TIMESTAMP_FORMAT

pathGlobFilter

PATTERN

  • Equivalências para PARQUET:

Chaves do Spark

Equivalências do Snowpark

pathGlobFilter

PATTERN

Cenários

Cenário 1

Entrada

Para CVS, aqui estão alguns exemplos:

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName('myapp').getOrCreate()

spark.read.csv("path3", None,None,None,None,None,None,True).show()
Copy

Saída

No código convertido, os parâmetros são adicionados como opções individuais à função cvs

from snowflake.snowpark import Session

spark = Session.builder.app_name('myapp', True).getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})

#EWI: SPRKPY1076 => Some of the included parameters are not supported in the csv function, the supported ones will be added into a option method.
spark.read.option("FIELD_DELIMITER", None).option("PARSE_HEADER", True).option("FIELD_OPTIONALLY_ENCLOSED_BY", None).csv("path3").show()
Copy

Cenário 2

Entrada

Para JSON, aqui estão alguns exemplos:

from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('myapp').getOrCreate()
spark.read.json("/myPath/jsonFile/", dateFormat='YYYY/MM/DD').show()
Copy

Saída

No código convertido, os parâmetros são adicionados como opções individuais à função json

from snowflake.snowpark import Session
spark = Session.builder.app_name('myapp', True).getOrCreate()
#EWI: SPRKPY1076 => Some of the included parameters are not supported in the json function, the supported ones will be added into a option method.

spark.read.option("DATE_FORMAT", 'YYYY/MM/DD').json("/myPath/jsonFile/").show()
Copy
Cenário 3

Entrada

Para PARQUET, aqui estão alguns exemplos:

from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('myapp').getOrCreate()

spark.read.parquet("/path/to/my/file.parquet", pathGlobFilter="*.parquet").show()
Copy

Saída

No código convertido, os parâmetros são adicionados como opções individuais à função parquet

from snowflake.snowpark import Session

spark = Session.builder.app_name('myapp', True).getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})

#EWI: SPRKPY1076 => Some of the included parameters are not supported in the parquet function, the supported ones will be added into a option method.
#EWI: SPRKPY1029 => The parquet function require adjustments, in Snowpark the parquet files needs to be located in an stage. See the documentation for more info.

spark.read.option("PATTERN", "*.parquet").parquet("/path/to/my/file.parquet")
Copy

Recomendações adicionais

SPRKPY1066

Mensagem: O elemento Spark não se aplica, pois o Snowflake usa o mecanismo de micropartição criado automaticamente.

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso de elementos relacionados a partições:

Esses elementos não se aplicam devido ao uso de micropartições do Snowflake.

Código de entrada

Neste exemplo sortWithinPartitions ele é usado para criar uma partição em um DataFrame classificado pela coluna especificada.

df = spark.createDataFrame([(2, "Alice"), (5, "Bob")], schema=["age", "name"])
df.sortWithinPartitions("age", ascending=False)
Copy

Código de saída

O SMA adiciona uma mensagem EWI indicando que o elemento Spark não é necessário.

df = spark.createDataFrame([(2, "Alice"), (5, "Bob")], schema=["age", "name"])
#EWI: SPRKPY1066 => The element does not apply since snowflake use micro-partitioning mechanism are created automatically.
df.sortWithinPartitions("age", ascending=False)
Copy

Correção recomendada

Remova o uso do elemento.

df = spark.createDataFrame([(2, "Alice"), (5, "Bob")], schema=["age", "name"])
Copy

Recomendações adicionais

SPRKPY1037

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.functions.sort_array tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.sort_array, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.sort_array que gera esse EWI. Neste exemplo, a função sort_array é usada para classificar a matriz numbers em ordem crescente e decrescente.

df = spark.createDataFrame([(1, [3, 1, 2]), (2, [10, 5, 8]), (3, [6, 4, 7])], ["id", "numbers"])
df_sorted_asc = df.withColumn("sorted_numbers_asc", sort_array("numbers", asc=True))
df_sorted_desc = df.withColumn("sorted_numbers_desc", sort_array("numbers", asc=False))
Copy

Saída

O SMA adiciona o EWI SPRKPY1037 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([(1, [3, 1, 2]), (2, [10, 5, 8]), (3, [6, 4, 7])], ["id", "numbers"])
#EWI: SPRKPY1037 => pyspark.sql.functions.sort_array has a workaround, see documentation for more info
df_sorted_asc = df.withColumn("sorted_numbers_asc", sort_array("numbers", asc=True))
#EWI: SPRKPY1037 => pyspark.sql.functions.sort_array has a workaround, see documentation for more info
df_sorted_desc = df.withColumn("sorted_numbers_desc", sort_array("numbers", asc=False))
Copy

Correção recomendada

Como solução alternativa, você pode importar o pacote snowpark_extensions, que fornece uma extensão para a função sort_array.

import snowpark_extensions

df = spark.createDataFrame([(1, [3, 1, 2]), (2, [10, 5, 8]), (3, [6, 4, 7])], ["id", "numbers"])
df_sorted_asc = df.withColumn("sorted_numbers_asc", sort_array("numbers", asc=True))
df_sorted_desc = df.withColumn("sorted_numbers_desc", sort_array("numbers", asc=False))
Copy

Recomendações adicionais

SPRKPY1003

Message : Ocorreu um erro ao carregar a tabela de símbolos.

Category : Erro de conversão.

Descrição

Esse problema aparece quando há um erro ao processar os símbolos na tabela de símbolos. A tabela de símbolos faz parte da arquitetura subjacente do SMA, permitindo conversões mais complexas. Esse erro pode ser devido a uma declaração inesperada no código-fonte.

Recomendações adicionais

  • É improvável que isso seja um erro no próprio código-fonte, mas sim um erro na forma como a ferramenta processa o código-fonte. A melhor solução seria publicar um problema no SMA.

  • Para obter mais suporte, você pode enviar um e-mail para sma-support@snowflake.com ou publicar um problema no SMA.

SPRKPY1052

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 2.8.0

Mensagem: pyspark.sql.session.SparkSession.Builder.enableHiveSupport tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.sql.session.SparkSession.Builder.enableHiveSupport que tem uma solução alternativa.

Cenário

Entrada

Abaixo está um exemplo que configura o SparkSession e habilita o suporte para Hive usando o método enableHiveSupport.

spark = Session.builder.appName("Merge_target_table")\
        .config("spark.port.maxRetries","100") \
        .enableHiveSupport().getOrCreate()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1052 indicando que uma solução alternativa pode ser implementada.

#EWI: SPRKPY1052 => pyspark.sql.session.SparkSession.Builder.enableHiveSupport has a workaround, see documentation for more info
spark = Session.builder.appName("Merge_target_table")\
        .config("spark.port.maxRetries","100") \
        .enableHiveSupport().getOrCreate()
Copy

Correção recomendada

Remova o uso da função enableHiveSupport porque ela não é necessária no Snowpark.

spark = Session.builder.appName("Merge_target_table")\
        .config("spark.port.maxRetries","100") \
        .getOrCreate()
Copy

Recomendações adicionais

SPRKPY1043

Mensagem: pyspark.sql.functions.posexplode_outer tem uma solução alternativa

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.posexplode_outer, que tem uma solução alternativa.

Cenários

Há alguns cenários com os quais esse método pode lidar, dependendo do tipo de coluna que é passada como parâmetro: pode ser uma lista de valores ou um mapa/diretório (chaves/valores).

Cenário 1

Entrada

Abaixo está um exemplo que mostra o uso de posexplode_outer passando uma lista de valores.

df = spark.createDataFrame(
    [
        (1, ["foo", "bar"]),
        (2, []),
        (3, None)],
    ("id", "an_array"))

df.select("id", "an_array", posexplode_outer("an_array")).show()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1043 indicando que uma solução alternativa pode ser implementada.

df = spark.createDataFrame(
    [
        (1, ["foo", "bar"]),
        (2, []),
        (3, None)],
    ("id", "an_array"))
#EWI: SPRKPY1043 => pyspark.sql.functions.posexplode_outer has a workaround, see documentation for more info

df.select("id", "an_array", posexplode_outer("an_array")).show()
Copy

Correção recomendada

Para ter o mesmo comportamento, use o método functions.flatten enviando o parâmetro outer em True, elimine as colunas extras e renomeie os nomes das colunas de índice e valor.

df = spark.createDataFrame(
    [
        (1, ["foo", "bar"]),
        (2, []),
        (3, None)],
    ("id", "an_array"))

df.select(
    flatten(df.an_array, outer=True))\
    .drop("DATA", "SEQ", "KEY", "PATH", "THIS")\
    .rename({"INDEX": "pos", "VALUE": "col"}).show()
Copy
Cenário 2

Entrada

Abaixo está outro exemplo de uso do posexplode_outer passando um mapa/dicionário (chaves/valores)

df = spark.createDataFrame(
    [
        (1, {"x": 1.0}),
        (2, {}),
        (3, None)],
    ("id", "a_map"))

df.select(posexplode_outer(df.a_map)).show()
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1043 indicando que uma solução alternativa pode ser implementada.

df = spark.createDataFrame(
    [
        (1, {"x": "Ashi Garami"}),
        (2, {}),
        (3, None)],
    ("id", "a_map"))
#EWI: SPRKPY1043 => pyspark.sql.functions.posexplode_outer has a workaround, see documentation for more info

df.select(posexplode_outer(df.a_map)).show()
Copy

Correção recomendada

Como solução alternativa, você pode usar functions.row_number para obter a posição e functions.explode_outer com o nome do campo para obter o valor da chave/valor para dicionários.

df = spark.createDataFrame(
    [
        (1, {"x": "Ashi Garami"}),
        (2,  {}),
        (3, None)],
    ("id", "a_map"))

window = Window.orderBy(col("id").asc())

df.select(
    row_number().over(window).alias("pos"),
          explode_outer(df.a_map)).show()
Copy

Observação: usar row_number não é totalmente equivalente, pois começa com 1 (não zero como o método spark)

Recomendações adicionais

SPRKPY1012

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.dataframe.DataFrameStatFunctions.writeTo tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.dataframe.DataFrameStatFunctions.writeTo que tem uma solução alternativa.

Cenário

Entrada

Neste exemplo, o dataframe df é gravado em uma tabela Spark «table».

writer = df.writeTo("table")
Copy

Saída

O SMA retorna o EWI SPRKPY1012 sobre a linha em que DataFrameStatFunctions.writeTo é usado, para que você possa identificar o local a ser corrigido.

#EWI: SPRKPY1012 => pyspark.sql.dataframe.DataFrameStatFunctions.writeTo has a workaround, see documentation for more info
writer = df.writeTo("table")
Copy

Correção recomendada

Em vez disso, use df.write.SaveAsTable().

import df.write as wt
writer = df.write.save_as_table(table)
Copy

Recomendações adicionais

SPRKPY1084

Esse código de problema foi depreciado desde o Spark Conversion Core 4.12.0

Mensagem: pyspark.sql.readwriter.DataFrameWriter.option não é compatível.

Categoria: Aviso

Descrição

A função pyspark.sql.readwriter.DataFrameWriter.option não é suportada.

Cenário

Código de entrada

Abaixo está um exemplo usando o método option, esse método é usado para adicionar configurações adicionais ao gravar os dados de um DataFrame.

path_csv_file = "/path/to/file.csv"
data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

df.write.option("header", True).csv(csv_file_path)
df.write.option("sep", ";").option("lineSep","-").csv(csv_file_path)
Copy

Código de saída

A ferramenta adiciona esse EWI SPRKPY1084 no código de saída para que você saiba que essa função não é compatível com o Snowpark.

path_csv_file = "/path/to/file.csv"
data = [
        ("John", 30, "New York"),
        ("Jane", 25, "San Francisco")
    ]

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])

#EWI: SPRKPY1084 => The pyspark.sql.readwriter.DataFrameWriter.option function is not supported.

df.write.option("header", True).csv(csv_file_path)
#EWI: SPRKPY1084 => The pyspark.sql.readwriter.DataFrameWriter.option function is not supported.
df.write.option("sep", ";").option("lineSep","-").csv(csv_file_path)
Copy

Correção recomendada

O método pyspark.sql.readwriter.DataFrameWriter.option não tem uma correção recomendada.

Recomendações adicionais

SPRKPY1026

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core 4.3.2

Mensagem: pyspark.sql.readwriter.DataFrameReader.csv tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.readwriter.DataFrameReader.csv, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.readwriter.DataFrameReader.csv que gera este EWI. Neste exemplo, a função csv é usada para ler vários arquivos .csv com um determinado esquema e usa algumas opções extras, como encoding, header e sep para ajustar o comportamento da leitura dos arquivos.

file_paths = [
  "path/to/your/file1.csv",
  "path/to/your/file2.csv",
  "path/to/your/file3.csv",
]

df = session.read.csv(
  file_paths,
  schema=my_schema,
  encoding="UTF-8",
  header=True,
  sep=","
)
Copy

Saída

O SMA adiciona o EWI SPRKPY1026 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

file_paths = [
  "path/to/your/file1.csv",
  "path/to/your/file2.csv",
  "path/to/your/file3.csv",
]

#EWI: SPRKPY1026 => pyspark.sql.readwriter.DataFrameReader.csv has a workaround, see documentation for more info
df = session.read.csv(
  file_paths,
  schema=my_schema,
  encoding="UTF-8",
  header=True,
  sep=","
)
Copy

Correção recomendada

Nesta seção, explicamos como configurar o parâmetro path, o parâmetro schema e algumas opções para fazê-los funcionar no Snowpark.

1. parâmetro path

O Snowpark exige que o parâmetro path seja um local de estágio, portanto, como solução alternativa, você pode criar um estágio temporário e adicionar cada arquivo .csv a esse estágio usando o prefixo file://.

2. parâmetro schema

O Snowpark não permite definir schema como um parâmetro da função csv. Como solução alternativa, você pode usar a função snowflake.snowpark.DataFrameReader.schema.

3. parâmetros de options

O Snowpark não permite definir as opções extras como parâmetros da função csv. Como solução alternativa, para muitos deles, você pode usar a função snowflake.snowpark.DataFrameReader.option para especificar esses parâmetros como opções do DataFrameReader.

Nota

As seguintes opções não são suportadas pelo Snowpark:

  • columnNameOfCorruptRecord

  • emptyValue

  • enforceSchema

  • header

  • ignoreLeadingWhiteSpace

  • ignoreTrailingWhiteSpace

  • inferSchema

  • locale

  • maxCharsPerColumn

  • maxColumns

  • mode

  • multiLine

  • nanValue

  • negativoInf

  • nullValue

  • positivoInf

  • quoteAll

  • samplingRatio

  • timestampNTZFormat

  • unescapedQuoteHandling

Abaixo está o exemplo completo de como o código de entrada deve ficar depois de aplicar as sugestões mencionadas acima para fazê-lo funcionar no Snowpark:

stage = f'{session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {stage}')

session.file.put(f"file:///path/to/your/file1.csv", f"@{stage}")
session.file.put(f"file:///path/to/your/file2.csv", f"@{stage}")
session.file.put(f"file:///path/to/your/file3.csv", f"@{stage}")

df = session.read.schema(my_schema).option("encoding", "UTF-8").option("sep", ",").csv(stage)
Copy

Recomendações adicionais

SPRKPY1077

Mensagem: o código SQL incorporado não pode ser processado.

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta um código SQL incorporado que não pode ser convertido para o Snowpark.

Consulte a seção de código SQL incorporado para obter mais informações.

Cenário

Entrada

Neste exemplo, o código SQL está incorporado em uma variável chamada query, que é usada como parâmetro para o método Pyspark.sql.

query = f"SELECT * from myTable"
spark.sql(query)
Copy

Saída

O SMA detecta que o parâmetro PySpark.sql é uma variável e não um código SQL, portanto, a mensagem EWI SPRKPY1077 é adicionada à linha PySpark.sql.

query = f"SELECT * myTable"
#EWI: SPRKPY1077 => SQL embedded code cannot be processed.
spark.sql(query)
Copy

Recomendações adicionais

  • Para a transformação de SQL, esse código deve estar diretamente dentro como parâmetro do método apenas como valores de cadeia de caracteres e sem interpolação. Verifique o envio de SQL para a função PySpark.SQL para validar sua funcionalidade no Snowflake.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1067

Mensagem: O pyspark.sql.functions.split tem parâmetros que não são suportados pelo Snowpark.

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.split com mais de dois parâmetros ou um padrão regex como parâmetro; ambos os casos não são suportados.

Cenários

Cenário 1

Código de entrada

Neste exemplo, a função split tem mais de dois parâmetros.

df.select(split(columnName, ",", 5))
Copy

Código de saída

A ferramenta adiciona esse EWI no código de saída para informar que essa função não é suportada quando tem mais de dois parâmetros.

#EWI: SPRKPY1067 => Snowpark does not support split functions with more than two parameters or containing regex pattern. See documentation for more info.
df.select(split(columnName, ",", 5))
Copy

Correção recomendada

Mantenha a função split com apenas dois parâmetros.

df.select(split(columnName, ","))
Copy
Cenário 2

Código de entrada

Neste exemplo, a função split tem um padrão regex como parâmetro.

df.select(split(columnName, "^([\d]+-[\d]+-[\d])"))
Copy

Código de saída

A ferramenta adiciona esse EWI no código de saída para informar que essa função não é suportada quando tem um padrão regex como parâmetro.

#EWI: SPRKPY1067 => Snowpark does not support split functions with more than two parameters or containing regex pattern. See documentation for more info.
df.select(split(columnName, "^([\d]+-[\d]+-[\d])"))
Copy

Correção recomendada

A assinatura do spark para esse método functions.split(str: ColumnOrName, pattern: str, limit: int = - 1) não corresponde exatamente ao método no Snowpark functions.split(str: Union[Column, str], pattern: Union[Column, str]) portanto, por enquanto, o cenário que usa expressão regular não tem uma correção recomendada.

Recomendações adicionais

SPRKPY1036

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.column.Column.getField tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.column.Column.getField, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.column.Column.getField que gera esse EWI. Neste exemplo, a função getField é usada para extrair o nome da coluna info.

df = spark.createDataFrame([(1, {"name": "John", "age": 30}), (2, {"name": "Jane", "age": 25})], ["id", "info"])
df_with_name = df.withColumn("name", col("info").getField("name"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1036 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([(1, {"name": "John", "age": 30}), (2, {"name": "Jane", "age": 25})], ["id", "info"])
#EWI: SPRKPY1036 => pyspark.sql.column.Column.getField has a workaround, see documentation for more info
df_with_name = df.withColumn("name", col("info").getField("name"))
Copy

Correção recomendada

Como solução alternativa, você pode usar o operador de indexador de coluna do Snowpark com o nome do campo como índice.

df = spark.createDataFrame([(1, {"name": "John", "age": 30}), (2, {"name": "Jane", "age": 25})], ["id", "info"])
df_with_name = df.withColumn("name", col("info")["name"])
Copy

Recomendações adicionais

SPRKPY1002

Message : < elemento > não é suportado, elemento Spark não é suportado.

Category : Erro de conversão.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de um elemento que não é compatível com o Snowpark e não tem seu próprio código de erro associado a ele. Esse é o código de erro genérico usado pelo SMA para um elemento sem suporte.

Recomendações adicionais

  • Mesmo que a opção ou o elemento da mensagem não seja compatível, isso não significa que não seja possível encontrar uma solução. Isso significa apenas que a ferramenta em si não consegue encontrar a solução.

  • Se encontrou um elemento não suportado de uma biblioteca pyspark.ml, considere uma abordagem alternativa. Há guias adicionais disponíveis para solucionar problemas relacionados ao ml, como este do Snowflake.

  • Verifique se o código-fonte tem a sintaxe correta. (Você pode usar o arquivo issues.csv para determinar onde estão ocorrendo os erros de conversão) Se a sintaxe estiver correta, informe que encontrou um erro de conversão em um elemento específico usando a opção de Relatar um problema no SMA. Inclua a linha de código que estava causando o erro na descrição quando registrar esse problema.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1053

Mensagem: Ocorreu um erro ao extrair os arquivos dbc.

Categoria: Aviso.

Descrição

Esse problema aparece quando um arquivo dbc não pode ser extraído. Esse aviso pode ser causado por um ou mais dos seguintes motivos: muito pesado, inacessível, somente leitura, etc.

Recomendações adicionais

  • Como solução alternativa, você pode verificar o tamanho do arquivo se ele for muito pesado para ser processado. Além disso, analise se a ferramenta pode acessá-la para evitar problemas de acesso.

  • Para obter mais suporte, envie um e-mail para snowconvert-info@snowflake.com. Se tiver um contrato de suporte com a Snowflake, entre em contato com seu engenheiro de vendas para que ele possa direcionar suas necessidades de suporte.

SPRKPY1080

Mensagem: O valor de SparkContext é substituído pela variável “session”.

Categoria: Aviso

Descrição

O contexto do Spark é armazenado em uma variável chamada session que cria uma sessão do Snowpark.

Cenário

Entrada

Este snippet descreve um SparkContext

## Input Code
from pyspark import SparkContext
from pyspark.sql import SparkSession

def example1():

    sc = SparkContext("local[*]", "TestApp")

    sc.setLogLevel("ALL")
    sc.setLogLevel("DEBUG")
Copy

Saída

Nesse código de saída, o SMA substituiu o PySpark.SparkContext por um SparkSession, observe que o SMA também adiciona um modelo para substituir a conexão no arquivo «connection.json» e, em seguida, carrega essa configuração na variável connection_parameter.

## Output Code
import logging
import sys
import json
from snowflake.snowpark import Session
from snowflake.snowpark import Session

def example1():
    jsonFile = open("connection.json")
    connection_parameter = json.load(jsonFile)
    jsonFile.close()
    #EWI: SPRKPY1080 => The value of SparkContext is replaced with 'session' variable.
    sc = Session.builder.configs(connection_parameter).getOrCreate()
    sc.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
    logging.basicConfig(stream = sys.stdout, level = logging.NOTSET)
    logging.basicConfig(stream = sys.stdout, level = logging.DEBUG)
Copy

Correção recomendada

O arquivo de configuração «connection.json» deve ser atualizado com as informações de conexão necessárias:

{
  "user": "my_user",
  "password": "my_password",
  "account": "my_account",
  "role": "my_role",
  "warehouse": "my_warehouse",
  "database": "my_database",
  "schema": "my_schema"
}
Copy

Recomendações adicionais

SPRKPY1073

Mensagem: pyspark.sql.functions.udf sem parâmetros ou parâmetro de tipo de retorno não são suportados

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.udf como função ou decorador e não é suportado em dois casos específicos, quando não tem parâmetros ou parâmetro de tipo de retorno.

Cenários

Cenário 1

Entrada

No Pyspark, você pode criar uma Função Definida pelo Usuário sem parâmetros de entrada ou de tipo de retorno:

from pyspark.sql import SparkSession, DataFrameStatFunctions
from pyspark.sql.functions import col, udf

spark = SparkSession.builder.getOrCreate()
data = [['Q1', 'Test 1'],
        ['Q2', 'Test 2'],
        ['Q3', 'Test 1'],
        ['Q4', 'Test 1']]

columns = ['Quadrant', 'Value']
df = spark.createDataFrame(data, columns)

my_udf = udf(lambda s: len(s))
df.withColumn('Len Value' ,my_udf(col('Value')) ).show()
Copy

Saída

O Snowpark requer os tipos de entrada e retorno para a função Udf. Porque eles não são fornecidos e o SMA não pode usar esses parâmetros.

from snowflake.snowpark import Session, DataFrameStatFunctions
from snowflake.snowpark.functions import col, udf

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 'Test 1'],
        ['Q2', 'Test 2'],
        ['Q3', 'Test 1'],
        ['Q4', 'Test 1']]

columns = ['Quadrant', 'Value']
df = spark.createDataFrame(data, columns)
#EWI: SPRKPY1073 => pyspark.sql.functions.udf function without the return type parameter is not supported. See documentation for more info.
my_udf = udf(lambda s: len(s))

df.withColumn('Len Value' ,my_udf(col('Value')) ).show()
Copy

Correção recomendada

Para corrigir esse cenário, é necessário adicionar a importação para os tipos de retorno de entrada e saída e, em seguida, os parâmetros de retornotype e input_types[] na função udf _my_udf.

from snowflake.snowpark import Session, DataFrameStatFunctions
from snowflake.snowpark.functions import col, udf
from snowflake.snowpark.types import IntegerType, StringType

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 'Test 1'],
        ['Q2', 'Test 2'],
        ['Q3', 'Test 1'],
        ['Q4', 'Test 1']]

columns = ['Quadrant', 'Value']
df = spark.createDataFrame(data, columns)

my_udf = udf(lambda s: len(s), return_type=IntegerType(), input_types=[StringType()])

df.with_column("result", my_udf(df.Value)).show()
Copy
Cenário 2

No PySpark, você pode usar um decorador @udf sem parâmetros

Entrada

from pyspark.sql.functions import col, udf

spark = SparkSession.builder.getOrCreate()
data = [['Q1', 'Test 1'],
        ['Q2', 'Test 2'],
        ['Q3', 'Test 1'],
        ['Q4', 'Test 1']]

columns = ['Quadrant', 'Value']
df = spark.createDataFrame(data, columns)

@udf()
def my_udf(str):
    return len(str)


df.withColumn('Len Value' ,my_udf(col('Value')) ).show()
Copy

Saída

No Snowpark, todos os parâmetros de um decorador udf são necessários.

from snowflake.snowpark.functions import col, udf

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 'Test 1'],
        ['Q2', 'Test 2'],
        ['Q3', 'Test 1'],
        ['Q4', 'Test 1']]

columns = ['Quadrant', 'Value']
df = spark.createDataFrame(data, columns)

#EWI: SPRKPY1073 => pyspark.sql.functions.udf decorator without parameters is not supported. See documentation for more info.

@udf()
def my_udf(str):
    return len(str)

df.withColumn('Len Value' ,my_udf(col('Value')) ).show()
Copy

Correção recomendada

Para corrigir esse cenário, é necessário adicionar a importação para os tipos de retorno da entrada e da saída e, em seguida, os parâmetros de return_type e input_types[] no decorador udf @udf.

from snowflake.snowpark.functions import col, udf
from snowflake.snowpark.types import IntegerType, StringType

spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Q1', 'Test 1'],
        ['Q2', 'Test 2'],
        ['Q3', 'Test 1'],
        ['Q4', 'Test 1']]

columns = ['Quadrant', 'Value']
df = spark.createDataFrame(data, columns)

@udf(return_type=IntegerType(), input_types=[StringType()])
def my_udf(str):
    return len(str)

df.withColumn('Len Value' ,my_udf(col('Value')) ).show()
Copy

Recomendações adicionais

SPRKPY1022

Mensagem: pyspark.sql.functions.log10 tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.functions.log10, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.functions.log10 que gera esse EWI. Neste exemplo, a função log10 é usada para calcular o logaritmo de base 10 da coluna value.

df = spark.createDataFrame([(1,), (10,), (100,), (1000,), (10000,)], ["value"])
df_with_log10 = df.withColumn("log10_value", log10(df["value"]))
Copy

Saída

O SMA adiciona o EWI SPRKPY1022 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([(1,), (10,), (100,), (1000,), (10000,)], ["value"])
#EWI: SPRKPY1022 => pyspark.sql.functions.log10 has a workaround, see documentation for more info
df_with_log10 = df.withColumn("log10_value", log10(df["value"]))
Copy

Correção recomendada

Como solução alternativa, você pode usar a função snowflake.snowpark.functions.log passando o valor literal 10 como base.

df = spark.createDataFrame([(1,), (10,), (100,), (1000,), (10000,)], ["value"])
df_with_log10 = df.withColumn("log10_value", log(10, df["value"]))
Copy

Recomendações adicionais

SPRKPY1016

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 0.11.7

Mensagem: pyspark.sql.functions.collect_set tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.collect_set, que tem uma solução alternativa.

Cenário

Entrada

Usando o conjuntocollect para obter os elementos de _colname sem duplicatas:

col = collect_set(colName)
Copy

Saída

O SMA retorna o EWI SPRKPY1016 sobre a linha em que collect_set é usado, para que você possa identificar onde corrigir.

#EWI: SPRKPY1016 => pyspark.sql.functions.collect_set has a workaround, see documentation for more info
col = collect_set(colName)
Copy

Correção recomendada

Use a função array_agg e adicione um segundo argumento com o valor True.

col = array_agg(col, True)
Copy

Recomendações adicionais

SPRKPY1047

Aviso

Esse código de problema está obsoleto desde o Spark Conversion Core Version 4.6.0

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.context.SparkContext.setLogLevel que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso do método setLogLevel.

sparkSession.sparkContext.setLogLevel("WARN")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1047 indicando que uma solução alternativa pode ser implementada.

#EWI: SPRKPY1047 => pyspark.context.SparkContext.setLogLevel has a workaround, see documentation for more info
sparkSession.sparkContext.setLogLevel("WARN")
Copy

Correção recomendada

Substitua o uso da função setLogLevel por logging.basicConfig que fornece um conjunto de funções de conveniência para uso simples de registro. Para usá-lo, precisamos importar dois módulos, «logging» e «sys», e a constante de nível deve ser substituída usando a «Tabela de níveis equivalentes»:

import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.WARNING)
Copy
  • Tabela de níveis equivalentes

Parâmetro de origem de nível

Parâmetro de destino de nível

«ALL»

Isso não tem equivalente

«DEBUG»

logging.DEBUG

«ERROR»

logging.ERROR

«FATAL»

logging.CRITICAL

«INFO»

logging.INFO

«OFF»

logging.NOTSET

«TRACE»

Isso não tem equivalente

«WARN»

logging.WARNING

Recomendações adicionais

SPRKPY1057

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 4.8.0

Mensagem: O argumento da opção PySpark Dataframe contém um valor que não é um literal e, portanto, não pode ser avaliado

Categoria: Aviso.

Descrição

Esse código de problema está obsoleto. Se você estiver usando uma versão mais antiga, atualize para a mais recente.

Recomendações adicionais

SPRKPY1006

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 4.8.0

Message : pyspark.context.SparkContext não é necessário

Category : Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.context.SparkContext, que não é necessário no Snowflake.

Cenário

Entrada

Neste exemplo, há dois contextos para criar conexões com um Spark Cluster

from pyspark import SparkContext

sql_context1 = SparkContext(my_sc1)
sql_context2 = SparkContext(sparkContext=my_sc2)
Copy

Saída

Como não há clusters no Snowflake, o contexto não é necessário. Observe que as variáveis my_sc1 e my_sc2, que contêm propriedades do Spark, podem não ser necessárias ou terão de ser adaptadas para corrigir o código.

from snowflake.snowpark import Session
#EWI: SPRKPY1006 => pyspark.sql.context.SparkContext is not required
sql_context1 = my_sc1
#EWI: SPRKPY1006 => pyspark.sql.context.SparkContext is not required

sql_context2 = my_sc2
Copy

Recomendações adicionais

  • Esse é um parâmetro desnecessário que está sendo removido com a inserção de um comentário de aviso. Não deve haver nenhuma ação por parte do usuário.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1032

Mensagem: _ spark element _ não está definido

Categoria: Erro de conversão

Descrição

Esse problema aparece quando o SMA não consegue determinar um status de mapeamento apropriado para um determinado elemento. Isso significa que o SMA ainda não sabe se esse elemento é compatível ou não com o Snowpark. Observe que esse é um código de erro genérico usado pelo SMA para qualquer elemento não definido.

Cenário

Entrada

Abaixo está um exemplo de uma função para a qual o SMA não conseguiu determinar um status de mapeamento adequado. Nesse caso, presuma que not_defined_function() é uma função válida PySpark e o código é executado.

sc.parallelize(["a", "b", "c", "d", "e"], 3).not_defined_function().collect()
Copy

Saída

O SMA adiciona o EWI SPRKPY1032 ao código de saída para informar que esse elemento não está definido.

#EWI: SPRKPY1032 => pyspark.rdd.RDD.not_defined_function is not defined
sc.parallelize(["a", "b", "c", "d", "e"], 3).not_defined_function().collect()
Copy

Correção recomendada

Para tentar identificar o problema, você pode realizar as seguintes validações:

  • Verifique se o código-fonte tem a sintaxe correta e se está escrito corretamente.

  • Verifique se está usando uma versão do PySpark compatível com o SMA. Para saber qual versão do PySpark é compatível com o SMA no momento da execução do SMA, examine a primeira página do arquivo DetailedReport.docx.

Se esse for um elemento válido do PySpark, informe que encontrou um erro de conversão nesse elemento específico usando a opção de Relatar um problema do SMA e inclua qualquer informação adicional que considere útil.

Observe que, se um elemento não estiver definido, isso não significa que ele não seja compatível com o Snowpark. Consulte a documentação do Snowpark para verificar se existe um elemento equivalente.

Recomendações adicionais

SPRKPY1063

Mensagem: pyspark.sql.pandas.functions.pandas_udf tem uma solução alternativa.

Categoria: Aviso

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.pandas.functions.pandas_udf, que tem uma solução alternativa.

Cenário

Entrada

A função pandas_udf é usada para criar funções definidas pelo usuário que trabalham com grandes quantidades de dados.

@pandas_udf(schema, PandasUDFType.GROUPED_MAP)
def modify_df(pdf):
    return pd.DataFrame({'result': pdf['col1'] + pdf['col2'] + 1})
df = spark.createDataFrame([(1, 2), (3, 4), (1, 1)], ["col1", "col2"])
new_df = df.groupby().apply(modify_df)
Copy

Saída

O SMA adiciona uma mensagem EWI indicando que o pandas_udf tem uma solução alternativa.

#EWI: SPRKPY1062 => pyspark.sql.pandas.functions.pandas_udf has a workaround, see documentation for more info
@pandas_udf(schema, PandasUDFType.GROUPED_MAP)

def modify_df(pdf):
    return pd.DataFrame({'result': pdf['col1'] + pdf['col2'] + 1})

df = spark.createDataFrame([(1, 2), (3, 4), (1, 1)], ["col1", "col2"])

new_df = df.groupby().apply(modify_df)
Copy

Correção recomendada

Especifique explicitamente os tipos de parâmetros como um novo parâmetro input_types e remova o parâmetro functionType, se aplicável. A função criada deve ser chamada dentro de uma instrução select.

@pandas_udf(
    return_type = schema,
    input_types = [PandasDataFrameType([IntegerType(), IntegerType()])]
)

def modify_df(pdf):
    return pd.DataFrame({'result': pdf['col1'] + pdf['col2'] + 1})

df = spark.createDataFrame([(1, 2), (3, 4), (1, 1)], ["col1", "col2"])

new_df = df.groupby().apply(modify_df) # You must modify function call to be a select and not an apply
Copy

Recomendações adicionais

SPRKPY1078

Mensagem: O argumento da função pyspark.context.SparkContext.setLogLevel não é um valor literal e, portanto, não pôde ser avaliado

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.context.SparkContext.setLogLevel com um argumento que não é um valor literal, por exemplo, quando o argumento é uma variável.

O SMA faz uma análise estática do seu código-fonte e, portanto, não é possível avaliar o conteúdo desse argumento e determinar um equivalente no Snowpark.

Cenário

Entrada

Neste exemplo, o logLevel é definido na variável my_log_level e, em seguida, my_log_level é usado como parâmetro pelo método setLogLevel.

my_log_level = "WARN"
sparkSession.sparkContext.setLogLevel(my_log_level)
Copy

Saída

O SMA não consegue avaliar o argumento do parâmetro de nível de registro, portanto, o EWI SPRKPY1078 é adicionado sobre a linha do registro transformado:

my_log_level = "WARN"
#EWI: SPRKPY1078 => my_log_level is not a literal value and therefore could not be evaluated. Make sure the value of my_log_level is a valid level in Snowpark. Valid log levels are: logging.CRITICAL, logging.DEBUG, logging.ERROR, logging.INFO, logging.NOTSET, logging.WARNING
logging.basicConfig(stream = sys.stdout, level = my_log_level)
Copy

Correção recomendada

Mesmo que o SMA não tenha conseguido avaliar o argumento, ele transformará a função pyspark.context.SparkContext.setLogLevel no equivalente do Snowpark. Certifique-se de que o valor do argumento level no código de saída gerado seja um nível de registro válido e equivalente no Snowpark, de acordo com a tabela abaixo:

Nível de registro do PySpark

Nível de registro do Snowpark equivalente

ALL

logging.NOTSET

DEBUG

logging.DEBUG

ERROR

logging.ERROR

FATAL

logging.CRITICAL

INFO

logging.INFO

OFF

logging.WARNING

TRACE

logging.NOTSET

WARN

logging.WARNING

Assim, a correção recomendada será semelhante:

my_log_level = logging.WARNING
logging.basicConfig(stream = sys.stdout, level = my_log_level)
Copy

Recomendações adicionais

SPRKPY1029

Mensagem: Esse problema aparece quando a ferramenta detecta o uso do pyspark.sql.readwriter.DataFrameReader.parquet. Essa função é compatível, mas algumas das diferenças entre o Snowpark e o Spark API podem exigir algumas alterações manuais.

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.readwriter.DataFrameReader.parquet. Essa função é compatível com o Snowpark, mas há algumas diferenças que exigiriam algumas alterações manuais.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.readwriter.DataFrameReader.parquet que gera essa função EWI.

file_paths = [
  "path/to/your/file1.parquet",
  "path/to/your/file2.parquet",
  "path/to/your/file3.parquet",
]

df = session.read.parquet(
  *file_paths,
  mergeSchema="true",
  pathGlobFilter="*file*",
  recursiveFileLookup="true",
  modifiedBefore="2024-12-31T00:00:00",
  modifiedAfter="2023-12-31T00:00:00"
)
Copy

Saída

O SMA adiciona o EWI SPRKPY1029 ao código de saída para que você saiba que essa função é compatível com o Snowpark, mas requer alguns ajustes manuais. Observe que as opções suportadas pelo Snowpark são transformadas em chamadas de função option e as que não são suportadas são removidas. Isso é explicado em mais detalhes nas próximas seções.

file_paths = [
  "path/to/your/file1.parquet",
  "path/to/your/file2.parquet",
  "path/to/your/file3.parquet"
]

#EWI: SPRKPY1076 => Some of the included parameters are not supported in the parquet function, the supported ones will be added into a option method.
#EWI: SPRKPY1029 => This issue appears when the tool detects the usage of pyspark.sql.readwriter.DataFrameReader.parquet. This function is supported, but some of the differences between Snowpark and the Spark API might require making some manual changes.
df = session.read.option("PATTERN", "*file*").parquet(
  *file_paths
)
Copy

Correção recomendada

Nesta seção, explicamos como configurar os parâmetros paths e options para fazê-los funcionar no Snowpark.

1. parâmetro paths

No Spark, esse parâmetro pode ser estar no local ou na nuvem. O Snowpark só aceita locais de nuvem que usam um estágio de snowflake. Assim, você pode criar um estágio temporal e adicionar cada arquivo a ele usando o prefixo file://.

2. parâmetro options

O Snowpark não permite definir as diferentes options como parâmetros da função parquet. Como solução alternativa, use as funções option ou options para especificar esses parâmetros como opções extras do DataFrameReader.

Observe que options do Snowpark não são exatamente iguais a options do PySpark, portanto, pode ser necessário fazer algumas alterações manuais. Veja a seguir uma explicação mais detalhada de como configurar as opções mais comuns do PySpark no Snowpark.

2.1 opção mergeSchema

O Parquet suporta a evolução do esquema, permitindo que os usuários comecem com um esquema simples e adicionem gradualmente mais colunas, conforme necessário. Isso pode resultar em vários arquivos de parquet com esquemas diferentes, mas compatíveis. No Snowflake, graças aos recursos infer_schema, você não precisa fazer isso e, portanto, a opção mergeSchema pode ser simplesmente removida.

2.2 opção pathGlobFilter

Se quiser carregar apenas um subconjunto de arquivos do estágio, use a opção pattern para especificar uma expressão regular que corresponda aos arquivos que deseja carregar. O SMA já automatiza isso, como pode ver no resultado desse cenário.

2.3 opção recursiveFileLookupstr

Essa opção não é suportada pelo Snowpark. A melhor recomendação é usar uma expressão regular como a opção pathGlobFilter para obter algo semelhante.

2.4 opção modifiedBefore / modifiedAfter

Tenha o mesmo resultado no Snowflake usando as colunas metadata.

Nota

As seguintes opções não são suportadas pelo Snowpark:

  • compression

  • datetimeRebaseMode

  • int96RebaseMode

  • mergeSchema

Abaixo está o exemplo completo de como o código de entrada deve ser transformado para que funcione no Snowpark:

from snowflake.snowpark.column import METADATA_FILE_LAST_MODIFIED, METADATA_FILENAME

temp_stage = f'{session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {temp_stage}')

session.file.put(f"file:///path/to/your/file1.parquet", f"@{temp_stage}")
session.file.put(f"file:///path/to/your/file2.parquet", f"@{temp_stage}")
session.file.put(f"file:///path/to/your/file3.parquet", f"@{temp_stage}")

df = session.read \
  .option("PATTERN", ".*file.*") \
  .with_metadata(METADATA_FILENAME, METADATA_FILE_LAST_MODIFIED) \
  .parquet(temp_stage) \
  .where(METADATA_FILE_LAST_MODIFIED < '2024-12-31T00:00:00') \
  .where(METADATA_FILE_LAST_MODIFIED > '2023-12-31T00:00:00')
Copy

Recomendações adicionais

  • No Snowflake, você pode aproveitar outras abordagens para a ingestão de dados de parquet, como:

  • Ao fazer uma migração, é uma boa prática aproveitar os relatórios do SMA para tentar criar um inventário de arquivos e determinar, após a modernização, para quais estágios/tabelas os dados serão mapeados.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1039

Aviso

Este código de problema está obsoleto

Mensagem: pyspark.sql.column.Column.getItem tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.column.Column.getItem, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.column.Column.getItem que gera esse EWI. Neste exemplo, a função getItem é usada para obter um item por posição e por chave.

df = spark.createDataFrame([(1, ["apple", "banana", "orange"]), (2, ["carrot", "avocado", "banana"])], ["id", "fruits"])
df.withColumn("first_fruit", col("fruits").getItem(0))

df = spark.createDataFrame([(1, {"apple": 10, "banana": 20}), (2, {"carrot": 15, "grape": 25}), (3, {"pear": 30, "apple": 35})], ["id", "fruit_quantities"])
df.withColumn("apple_quantity", col("fruit_quantities").getItem("apple"))
Copy

Saída

O SMA adiciona o EWI SPRKPY1039 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

df = spark.createDataFrame([(1, ["apple", "banana", "orange"]), (2, ["carrot", "avocado", "banana"])], ["id", "fruits"])
#EWI: SPRKPY1039 => pyspark.sql.column.Column.getItem has a workaround, see documentation for more info
df.withColumn("first_fruit", col("fruits").getItem(0))

df = spark.createDataFrame([(1, {"apple": 10, "banana": 20}), (2, {"carrot": 15, "grape": 25}), (3, {"pear": 30, "apple": 35})], ["id", "fruit_quantities"])
#EWI: SPRKPY1039 => pyspark.sql.column.Column.getItem has a workaround, see documentation for more info
df.withColumn("apple_quantity", col("fruit_quantities").getItem("apple"))
Copy

Correção recomendada

Como solução alternativa, você pode usar o operador de indexador de coluna Snowpark com o nome ou a posição do campo como índice.

df = spark.createDataFrame([(1, ["apple", "banana", "orange"]), (2, ["carrot", "avocado", "banana"])], ["id", "fruits"])
df.withColumn("first_fruit", col("fruits")[0])

df = spark.createDataFrame([(1, {"apple": 10, "banana": 20}), (2, {"carrot": 15, "grape": 25}), (3, {"pear": 30, "apple": 35})], ["id", "fruit_quantities"])
df.withColumn("apple_quantity", col("fruit_quantities")["apple"])
Copy

Recomendações adicionais

SPRKPY1068

Mensagem: toPandas contém colunas do tipo ArrayType que não são suportadas e têm uma solução alternativa.

Categoria: Aviso

Descrição

pyspark.sql.DataFrame.toPandas não funciona corretamente se houver colunas do tipo ArrayType. A solução alternativa para esses casos é converter essas colunas em um dicionário Python usando o método json.loads.

Cenário

Entrada

ToPandas retorna os dados do DataFrame original como um Pandas DataFrame.

sparkDF = spark.createDataFrame([
Row(a=1, b=2., c='string1', d=date(2000, 1, 1), e=datetime(2000, 1, 1, 12, 0)),
Row(a=2, b=3., c='string2', d=date(2000, 2, 1), e=datetime(2000, 1, 2, 12, 0))
])

pandasDF = sparkDF.toPandas()
Copy

Saída

A ferramenta adiciona este EWI para que você saiba que o toPandas não é suportado se houver colunas do tipo ArrayType, mas tem uma solução alternativa.

sparkDF = spark.createDataFrame([
Row(a=1, b=2., c='string1', d=date(2000, 1, 1), e=datetime(2000, 1, 1, 12, 0)),
Row(a=2, b=3., c='string2', d=date(2000, 2, 1), e=datetime(2000, 1, 2, 12, 0))
])
#EWI: SPRKPY1068 => toPandas doesn't work properly If there are columns of type ArrayType. The workaround for these cases is converting those columns into a Python Dictionary by using json.loads method. example: df[colName] = json.loads(df[colName]).
pandasDF = sparkDF.toPandas()
Copy

Correção recomendada

pandas_df = sparkDF.toPandas()

## check/convert all resulting fields from calling toPandas when they are of
## type ArrayType,
## they will be reasigned by converting them into a Python Dictionary
## using json.loads method​

for field in pandas_df.schema.fields:
    if isinstance(field.datatype, ArrayType):
        pandas_df[field.name] = pandas_df[field.name].apply(lambda x: json.loads(x) if x is not None else x)
Copy

Recomendações adicionais

SPRKPY1048

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 2.4.0

Mensagem: pyspark.sql.session.SparkSession.conf tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.session.SparkSession.conf que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de como definir uma configuração na propriedade conf.

spark.conf.set("spark.sql.crossJoin.enabled", "true")
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1048 indicando que uma solução alternativa pode ser implementada.

#EWI: SPRKPY1048 => pyspark.sql.session.SparkSession.conf has a workaround, see documentation for more info
spark.conf.set("spark.sql.crossJoin.enabled", "true")
Copy

Correção recomendada

SparkSession.conf é usado para passar algumas configurações específicas usadas apenas pelo Pyspark e não se aplica ao Snowpark. Você pode remover ou comentar o código

#spark.conf.set("spark.sql.crossJoin.enabled", "true")
Copy

Recomendações adicionais

SPRKPY1019

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 4.8.0

Mensagem: pyspark.sql.functions.datediff tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.datediff, que tem uma solução alternativa.

Cenário

Entrada

Neste exemplo, usamos o datediff para calcular a diferença de dia entre «today» e outras datas.

contacts = (contacts
            #days since last event
            .withColumn('daysSinceLastEvent', datediff(lit(today),'lastEvent'))
            #days since deployment
            .withColumn('daysSinceLastDeployment', datediff(lit(today),'lastDeploymentEnd'))
            #days since online training
            .withColumn('daysSinceLastTraining', datediff(lit(today),'lastTraining'))
            #days since last RC login
            .withColumn('daysSinceLastRollCallLogin', datediff(lit(today),'adx_identity_lastsuccessfullogin'))
            #days since last EMS login
            .withColumn('daysSinceLastEMSLogin', datediff(lit(today),'vms_lastuserlogin'))
           )
Copy

Saída

O SMA retorna o EWI SPRKPY1019 sobre a linha em que datediff é usado, para que você possa identificar onde corrigir.

from pyspark.sql.functions import datediff
#EWI: SPRKPY1019 => pyspark.sql.functions.datediff has a workaround, see documentation for more info
contacts = (contacts
            #days since last event
            .withColumn('daysSinceLastEvent', datediff(lit(today),'lastEvent'))
            #days since deployment
            .withColumn('daysSinceLastDeployment', datediff(lit(today),'lastDeploymentEnd'))
            #days since online training
            .withColumn('daysSinceLastTraining', datediff(lit(today),'lastTraining'))
            #days since last RC login
            .withColumn('daysSinceLastRollCallLogin', datediff(lit(today),'adx_identity_lastsuccessfullogin'))
            #days since last EMS login
            .withColumn('daysSinceLastEMSLogin', datediff(lit(today),'vms_lastuserlogin'))
           )
Copy

O SMA converte pyspark.sql.functions.datediff em snowflake.snowpark.functions.daydiff, que também calcula a diferença de dias entre duas datas.

Correção recomendada

datediff(part: string ,end: ColumnOrName, start: ColumnOrName)

Ação: Importar snowflake.snowpark.functions, que contém uma implementação da função datediff que requer um parâmetro extra para a parte de data e hora e permite mais versatilidade no cálculo de diferenças entre datas.

from snowflake.snowpark import Session
from snowflake.snowpark.functions import datediff
contacts = (contacts
            #days since last event
            .withColumn('daysSinceLastEvent', datediff('day', lit(today),'lastEvent'))
            #days since deployment
            .withColumn('daysSinceLastDeployment', datediff('day',lit(today),'lastDeploymentEnd'))
            #days since online training
            .withColumn('daysSinceLastTraining', datediff('day', lit(today),'lastTraining'))
            #days since last RC login
            .withColumn('daysSinceLastRollCallLogin', datediff('day', lit(today),'adx_identity_lastsuccessfullogin'))
            #days since last EMS login
            .withColumn('daysSinceLastEMSLogin', datediff('day', lit(today),'vms_lastuserlogin'))
           )
Copy

Recomendação

SPRKPY1009

Message : pyspark.sql.dataframe.DataFrame.approxQuantile tem uma solução alternativa

Category : Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.dataframe.DataFrame.approxQuantile que tem uma solução alternativa.

Cenário

Entrada

É importante entender que o Pyspark usa duas funções approxQuantile diferentes. Aqui, usamos a versão DataFrame approxQuantile

from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
data = [['Sun', 10],
        ['Mon', 64],
        ['Thr', 12],
        ['Wen', 15],
        ['Thu', 68],
        ['Fri', 14],
        ['Sat', 13]]

columns = ['Day', 'Ammount']
df = spark.createDataFrame(data, columns)
df.approxQuantile('Ammount', [0.25, 0.5, 0.75], 0)
Copy

Saída

O SMA retorna o EWI SPRKPY1009 sobre a linha em que approxQuantile é usado, para que você possa identificar onde corrigir.

from snowflake.snowpark import Session
spark = Session.builder.getOrCreate()
spark.update_query_tag({"origin":"sf_sit","name":"sma","version":{"major":0,"minor":0,"patch":0},"attributes":{"language":"Python"}})
data = [['Sun', 10],
        ['Mon', 64],
        ['Thr', 12],
        ['Wen', 15],
        ['Thu', 68],
        ['Fri', 14],
        ['Sat', 13]]

columns = ['Day', 'Ammount']
df = spark.createDataFrame(data, columns)
#EWI: SPRKPY1009 => pyspark.sql.dataframe.DataFrame.approxQuantile has a workaround, see documentation for more info
df.approxQuantile('Ammount', [0.25, 0.5, 0.75], 0)
Copy

Correção recomendada

Use o método aproxQuantile do Snowpark. Alguns parâmetros não correspondem, e por isso exigem ajustes manuais. Para o exemplo do código de saída, uma correção recomendada poderia ser:

from snowflake.snowpark import Session
...
df = spark.createDataFrame(data, columns)

df.stat.approx_quantile('Ammount', [0.25, 0.5, 0.75])
Copy

pyspark.sql.dataframe.DataFrame.approxQuantile relativeError parameter não existe no SnowPark.

Recomendações adicionais

SPRKPY1058

Mensagem: < método > com < chave > Não há suporte para a chave específica da plataforma.

Categoria: ConversionError

Descrição

Os métodos get e set do pyspark.sql.conf.RuntimeConfig não são compatíveis com uma chave específica da plataforma.

Cenários

Nem todos os usos dos métodos get ou set terão um EWI no código de saída. Esse EWI aparece quando a ferramenta detecta o uso desses métodos com uma chave específica da plataforma que não é compatível.

Cenário 1

Entrada

Veja a seguir um exemplo dos métodos get ou set com chaves compatíveis no Snowpark.

session.conf.set("use_constant_subquery_alias", False)
spark.conf.set("sql_simplifier_enabled", True)

session.conf.get("use_constant_subquery_alias")
session.conf.get("use_constant_subquery_alias")
Copy

Saída

Como as chaves são compatíveis com o Snowpark, a ferramenta não adiciona o EWI no código de saída.

session.conf.set("use_constant_subquery_alias", True)
session.conf.set("sql_simplifier_enabled", False)

session.conf.get("use_constant_subquery_alias")
session.conf.get("sql_simplifier_enabled")
Copy

Correção recomendada

Não há nenhuma correção recomendada para esse cenário.

Cenário 2

Entrada

Abaixo está um exemplo usando chaves não suportadas.

data =
    [
      ("John", 30, "New York"),
      ("Jane", 25, "San Francisco")
    ]

session.conf.set("spark.sql.shuffle.partitions", "50")
spark.conf.set("spark.yarn.am.memory", "1g")

session.conf.get("spark.sql.shuffle.partitions")
session = spark.conf.get("spark.yarn.am.memory")

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])
Copy

Saída

A ferramenta adiciona esse EWI SPRKPY1058 no código de saída para que você saiba que esses métodos não são compatíveis com uma chave específica da plataforma.

data =
    [
      ("John", 30, "New York"),
      ("Jane", 25, "San Francisco")
    ]

#EWI: SPRKPY1058 => pyspark.sql.conf.RuntimeConfig.set method with this "spark.sql.shuffle.partitions" Platform specific key is not supported.
spark.conf.set("spark.sql.shuffle.partitions", "50")
#EWI: SPRKPY1058 => pyspark.sql.conf.RuntimeConfig.set method with this "spark.yarn.am.memory" Platform specific key is not supported.
spark.conf.set("spark.yarn.am.memory", "1g")

#EWI: SPRKPY1058 => pyspark.sql.conf.RuntimeConfig.get method with this "spark.sql.shuffle.partitions" Platform specific key is not supported.
spark.conf.get("spark.sql.shuffle.partitions")
#EWI: SPRKPY1058 => pyspark.sql.conf.RuntimeConfig.get method with this "spark.yarn.am.memory" Platform specific key is not supported.
spark.conf.get("spark.yarn.am.memory")

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])
Copy

Correção recomendada

A correção recomendada é remover esses métodos.

data =
    [
      ("John", 30, "New York"),
      ("Jane", 25, "San Francisco")
    ]

df = spark.createDataFrame(data, schema=["Name", "Age", "City"])
Copy

Recomendações adicionais

SPRKPY1049

Aviso

Esse código de problema foi descontinuado desde o Spark Conversion Core Version 2.1.9

Mensagem: pyspark.sql.session.SparkSession.sparkContext tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.session.SparkSession. sparkContext que tem uma solução alternativa.

Cenário

Entrada

Abaixo está um exemplo que cria uma sessão spark e, em seguida, usa a propriedade SparkContext para imprimir o appName.

print("APP Name :"+spark.sparkContext.appName())
Copy

Saída

A ferramenta adiciona o EWI SPRKPY1049 indicando que uma solução alternativa pode ser implementada.

#EWI: SPRKPY1049 => pyspark.sql.session.SparkSession.sparkContext has a workaround, see documentation for more info
print("APP Name :"+spark.sparkContext.appName())
Copy

Correção recomendada

O SparkContext não é compatível com SnowPark, mas você pode acessar os métodos e as propriedades de SparkContext diretamente da instância Session.

## Pyspark
print("APP Name :"+spark.sparkContext.appName())
can be used in SnowPark removing the sparkContext as:
#Manual adjustment in SnowPark
print("APP Name :"+spark.appName());
Copy

Recomendações adicionais

SPRKPY1018

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 4.8.0

Mensagem: pyspark.sql.functions.date_sub tem uma solução alternativa

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso de pyspark.sql.functions.date_sub, que tem uma solução alternativa.

Cenário

Entrada

Neste exemplo, usamos date_add para calcular a data 5 dias antes da data atual para o dataframe df.

col = df.select(date_sub(df.colName, 5))
Copy

Saída

O SMA retorna o EWI SPRKPY1018 sobre a linha em que date_sub é usado, para que você possa identificar onde corrigir.

#EWI: SPRKPY1018 => pyspark.sql.functions.date_sub has a workaround, see documentation for more info
col = df.select(date_sub(df.colName, 5))
Copy

Correção recomendada

Importar snowflake.snowpark.functions, que contém uma implementação para a função date_sub.

from pyspark.sql.functions import date_sub
df.withColumn("date", date_sub(df.colName, 5))
Copy

Recomendações adicionais

SPRKPY1008

Mensagem: pyspark.sql.context.HiveContext não é necessário

Categoria: Aviso.

Descrição

Esse problema aparece quando a ferramenta detecta o uso do pyspark.sql.context.HiveContext, que não é necessário.

Cenário

Entrada

Este é um exemplo para criar uma conexão com um armazenamento do Hive.

from pyspark.sql import HiveContext
hive_context = HiveContext(sc)
df = hive_context.table("myTable")
df.show()
Copy

Saída

No Snowflake, não há Hive stores, portanto, o Hive Context não é necessário. Mesmo assim, você pode usar arquivos parquet no Snowflake; consulte este tutorial para saber como.

#EWI: SPRKPY1008 => pyspark.sql.context.HiveContext is not required
hive_context = sc
df = hive_context.table("myTable")
df.show()
Copy

a variável sc refere-se a um objeto de sessão do Snow Park

Correção recomendada

Para o código de saída no exemplo, você deve adicionar o objeto de sessão do Snow Park de forma semelhante a este código:

## Here manually we can add the Snowpark Session object via a json config file called connection.json
import json
from snowflake.snowpark import Session
jsonFile = open("connection.json")
connection_parameter = json.load(jsonFile)
jsonFile.close()
sc = Session.builder.configs(connection_parameter).getOrCreate()

hive_context = sc
df = hive_context.table("myTable")
df.show()
Copy

Recomendações adicionais

SPRKPY1059

Aviso

Esse código de problema foi depreciado desde o Spark Conversion Core Version 2.45.1

Mensagem: pyspark.storagelevel.StorageLevel tem uma solução alternativa, consulte a documentação.

Categoria: Aviso

Descrição

Atualmente, o uso do StorageLevel não é necessário no Snowpark, pois a Snowflake controla o armazenamento. Para obter mais informações, consulte o EWI SPRKPY1072

Recomendações adicionais

  • Atualize seu aplicativo para a versão mais recente.

  • Para obter mais suporte, envie um e-mail para sma-support@snowflake.com ou publique um problema no SMA.

SPRKPY1079

Mensagem: O argumento da função pyspark.context.SparkContext.setLogLevel não é um nível de registro PySpark válido

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.context.SparkContext.setLogLevel com um argumento que não é um nível de registro válido no PySpark e, portanto, não foi possível determinar um equivalente no Snowpark.

Cenário

Entrada

aqui o nível de registro usa «INVALID_LOG_LEVEL», que não é um nível de registro válido do Pyspark.

sparkSession.sparkContext.setLogLevel("INVALID_LOG_LEVEL")
Copy

Saída

O SMA não consegue reconhecer o nível de registro «INVALID_LOG_LEVEL», embora o SMA faça a conversão, o EWI SPRKPY1079 é adicionado para indicar um possível problema.

#EWI: SPRKPY1079 => INVALID_LOG_LEVEL is not a valid PySpark log level, therefore an equivalent could not be determined in Snowpark. Valid PySpark log levels are: ALL, DEBUG, ERROR, FATAL, INFO, OFF, TRACE, WARN
logging.basicConfig(stream = sys.stdout, level = logging.INVALID_LOG_LEVEL)
Copy

Correção recomendada

Certifique-se de que o nível de registro usado na função pyspark.context.SparkContext.setLogLevel seja um nível de registro válido no PySpark ou no Snowpark e tente novamente.

logging.basicConfig(stream = sys.stdout, level = logging.DEBUG)
Copy

Recomendações adicionais

SPRKPY1028

Mensagem: pyspark.sql.readwriter.DataFrameReader.orc tem uma solução alternativa, consulte a documentação para obter mais informações

Categoria: Aviso

Descrição

Esse problema aparece quando o SMA detecta o uso da função pyspark.sql.readwriter.DataFrameReader.orc, que tem uma solução alternativa.

Cenário

Entrada

Veja a seguir um exemplo de uso da função pyspark.sql.readwriter.DataFrameReader.orc que gera esse EWI. Neste exemplo, a função orc é usada para ler vários arquivos .orc e usa algumas opções extras, como mergeSchema e recursiveFileLookup para ajustar o comportamento da leitura dos arquivos.

file_paths = [
  "path/to/your/file1.orc",
  "path/to/your/file2.orc",
  "path/to/your/file3.orc",
]

df = session.read.orc(
  file_paths,
  mergeSchema="True",
  recursiveFileLookup="True"
)
Copy

Saída

O SMA adiciona o EWI SPRKPY1028 ao código de saída para que você saiba que essa função não é diretamente compatível com o Snowpark, mas tem uma solução alternativa.

file_paths = [
  "path/to/your/file1.orc",
  "path/to/your/file2.orc",
  "path/to/your/file3.orc",
]

#EWI: SPRKPY1028 => pyspark.sql.readwriter.DataFrameReader.orc has a workaround, see documentation for more info
df = session.read.orc(
  file_paths,
  mergeSchema="True",
  recursiveFileLookup="True"
)
Copy

Correção recomendada

Nesta seção, explicamos como configurar o parâmetro path e as options extras para que funcionem no Snowpark.

1. parâmetro path

O Snowpark exige que o parâmetro path seja um local de estágio, portanto, como solução alternativa, você pode criar um estágio temporário e adicionar cada arquivo .orc a esse estágio usando o prefixo file://.

2. parâmetros options

O Snowpark não permite definir as opções extras como parâmetros da função orc. Como solução alternativa, para muitos deles, você pode usar a função snowflake.snowpark.DataFrameReader.option para especificar esses parâmetros como opções do DataFrameReader.

Nota

As seguintes opções não são suportadas pelo Snowpark:

  • compression

  • mergeSchema

Abaixo está o exemplo completo de como o código de entrada deve ficar depois de aplicar as sugestões mencionadas acima para fazê-lo funcionar no Snowpark:

stage = f'{session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {stage}')

session.file.put(f"file:///path/to/your/file1.orc", f"@{stage}")
session.file.put(f"file:///path/to/your/file2.orc", f"@{stage}")
session.file.put(f"file:///path/to/your/file3.orc", f"@{stage}")

df = session.read.option(recursiveFileLookup, "True").orc(stage)
Copy

Recomendações adicionais

SPRKPY1038

Mensagem: _ spark element _ is not yet recognized

Categoria: Erro de conversão

Descrição

Esse problema aparece quando há um elemento PySpark em seu código-fonte que não foi reconhecido pelo SMA. Isso pode ocorrer por diferentes motivos, como:

  • Um elemento que não existe em PySpark.

  • Um elemento que foi adicionado em uma versão do PySpark que o SMA ainda não suporta.

  • Um erro interno do SMA ao processar o elemento.

Esse é um código de erro genérico usado pelo SMA para qualquer elemento não reconhecido.

Cenário

Entrada

Abaixo está um exemplo de uso de uma função que não pôde ser reconhecida pelo SMA porque ela não existe em PySpark.

from pyspark.sql import functions as F
F.unrecognized_function()
Copy

Saída

O SMA adiciona o EWI SPRKPY1038 ao código de saída para informar que esse elemento não pôde ser reconhecido.

from snowflake.snowpark import functions as F
#EWI: SPRKPY1038 => pyspark.sql.functions.non_existent_function is not yet recognized
F.unrecognized_function()
Copy

Correção recomendada

Para tentar identificar o problema, você pode realizar as seguintes validações:

  • Verificar se o elemento existe em PySpark.

  • Verifique se o elemento está escrito corretamente.

  • Verifique se está usando uma versão do PySpark compatível com o SMA. Para saber qual versão do PySpark é compatível com o SMA no momento da execução do SMA, examine a primeira página do arquivo DetailedReport.docx.

Se for um elemento válido do PySpark, informe que encontrou um erro de conversão nesse elemento específico usando a opção de Relatar um problema do SMA e inclua qualquer informação adicional que considere útil.

Observe que, se um elemento não puder ser reconhecido pelo SMA, isso não significa que ele não seja compatível com o Snowpark. Consulte a documentação do Snowpark para verificar se existe um elemento equivalente.

Recomendações adicionais

SPRKPY1069

Mensagem: Se o parâmetro partitionBy for uma lista, o Snowpark lançará um erro.

Categoria: Aviso

Descrição

Quando há um uso do método pyspark.sql.readwriter.DataFrameWriter.parquet em que se trata do parâmetro partitionBy, a ferramenta mostra o EWI.

Isso ocorre porque, no Snowpark, o DataFrameWriter.parquet suporta apenas um ColumnOrSqlExpr como parâmetro partitionBy.

Cenários

Cenário 1

Código de entrada:

Para esse cenário, o parâmetro partitionBy não é uma lista.

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])

df.write.parquet(file_path, partitionBy="age")
Copy

Código de saída:

A ferramenta adiciona o EWI SPRKPY1069 para que você saiba que o Snowpark gera um erro se o parâmetro for uma lista.

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])

#EWI: SPRKPY1069 => If partitionBy parameter is a list, Snowpark will throw and error.
df.write.parquet(file_path, partition_by = "age", format_type_options = dict(compression = "None"))
Copy

Correção recomendada

Não há uma correção recomendada para esse cenário porque a ferramenta sempre adiciona esse EWI apenas para o caso de o parâmetro partitionBy ser uma lista. Lembre-se de que, no Snowpark, só são aceitos locais de nuvem que usem um estágio de snowflake.

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])

stage = f'{Session.get_fully_qualified_current_schema()}.{_generate_prefix("TEMP_STAGE")}'
Session.sql(f'CREATE TEMPORARY STAGE IF NOT EXISTS {stage}').show()
Session.file.put(f"file:///path/to/data/file.parquet", f"@{stage}")

df.write.parquet(stage, partition_by = "age", format_type_options = dict(compression = "None"))
Copy
Cenário 2

Código de entrada:

Para esse cenário, o parâmetro partitionBy é uma lista.

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])

df.write.parquet(file_path, partitionBy=["age", "name"])
Copy

Código de saída:

A ferramenta adiciona o EWI SPRKPY1069 para que você saiba que o Snowpark gera um erro se o parâmetro for uma lista.

df = spark.createDataFrame([(25, "Alice", "150"), (30, "Bob", "350")], schema=["age", "name", "value"])

#EWI: SPRKPY1069 => If partitionBy parameter is a list, Snowpark will throw and error.
df.write.parquet(file_path, partition_by = ["age", "name"], format_type_options = dict(compression = "None"))
Copy

Correção recomendada

Se o valor do parâmetro for uma lista, substitua-o por um ColumnOrSqlExpr.

df.write.parquet(file_path, partition_by = sql_expr("age || name"), format_type_options = dict(compression = "None"))
Copy

Recomendações adicionais