Conhecer o código do Apache Spark para desenvolvedores do U-SQL
Importante
O Azure Data Lake Analytics se aposentou em 29 de fevereiro de 2024. Saiba mais nesse comunicado.
Para análise de dados, sua organização pode usar Azure Synapse Analytics ou Microsoft Fabric.
Esta seção fornece diretrizes de alto nível sobre como transformar scripts U-SQL para Apache Spark.
- Começa com uma comparação dos paradigmas de processamento de duas linguagens
- Fornece dicas sobre como:
- Transformar scripts, incluindo expressões de conjunto de linhas do U-SQL
- Código .NET
- Tipos de dados
- Objetos de catálogo
Conhecer a linguagem e os paradigmas de processamento do U-SQL e do Spark
Antes de começar a migrar os scripts U-SQL do Azure Data Lake Analytics para o Spark, é útil compreender a linguagem geral e as filosofias de processamento dos dois sistemas.
O U-SQL é uma linguagem de consulta declarativa semelhante ao SQL, que usa um paradigma de fluxo de dados, e permite que incorpore e escale o código do usuário escrito em .NET (por exemplo, C#), Python e R. As extensões de usuário podem implementar expressões simples ou funções definidas pelo usuário, mas também podem fornecer ao usuário, a capacidade de implementar os chamados de operadores definidos pelo usuário, que implementam operadores personalizados para executar transformações de nível de conjunto de linhas, extrações e gravação de saída.
O Spark é uma estrutura de escalabilidade que oferece várias vinculações de nomes em Scala, Java, Python, .NET etc., em que você basicamente escreve seu código em uma dessas linguagens, cria abstrações de dados chamadas RDD (conjuntos de dados distribuídos resilientes), dataframes e conjuntos de dados, e usa uma DSL (linguagem específica de domínio) semelhante ao LINQ para transformá-los. Ele também fornece o SparkSQL como uma sublinguagem declarativa nas abstrações de dataframe e conjunto de dados. A DSL fornece duas categorias de operações, transformações e ações. A aplicação de transformações às abstrações de dados não executará a transformação, mas criará o plano de execução que será enviado para avaliação com uma ação (por exemplo, gravar o resultado em uma tabela ou arquivo temporário ou imprimir o resultado).
Assim, ao traduzir um script U-SQL para um programa Spark, você terá que decidir qual linguagem deseja usar para pelo menos gerar a abstração do quadro de dados (que atualmente é a abstração de dados usada com mais frequência) e se deseja escrever as transformações declarativas do fluxo de dados usando DSL ou SparkSQL. Em alguns casos mais complexos, poderá ser necessário dividir o script U-SQL numa sequência de Spark e outros passos implementados com Lote do Microsoft Azure ou Azure Functions.
Além disso, o Azure Data Lake Analytics oferece U-SQL em um ambiente de serviço de trabalho sem servidor no qual os recursos são alocados para cada trabalho, enquanto o Azure Synapse Spark, o Azure Databricks e o Azure HDInsight oferecem o Spark na forma de um serviço de cluster ou com os chamados modelos de pool do Spark. Ao transformar a sua aplicação, terá de ter em conta as implicações de criar, dimensionar, escalar e desmantelar agora os clusters ou piscinas.
Transformar scripts U-SQL
Os scripts U-SQL seguem o seguinte padrão de processamento:
- Os dados são lidos a partir de arquivos não estruturados usando a instrução
EXTRACT
, um local ou uma especificação de conjunto de arquivos e o extrator definido pelo usuário e o esquema desejado; ou a partir de tabelas U-SQL (tabelas gerenciadas ou externas). É representado como um conjunto de linhas. - Os conjuntos de linhas são transformados em várias instruções U-SQL que aplicam expressões U-SQL aos conjuntos de linhas e produzem novos conjuntos de linhas.
- Por fim, os conjuntos de linhas resultantes são gerados em forma de arquivos usando a instrução
OUTPUT
, que especifica os locais e uma saída interna ou definida pelo usuário, ou são gerados como uma tabela U-SQL.
O script é avaliado lentamente, o que significa que cada etapa de extração e transformação é montada em uma árvore de expressão e avaliada globalmente (o fluxo de dados).
Os programas do Spark são semelhantes, no sentido de usar conectores do Spark para ler os dados e criar os dataframes, depois aplicar as transformações nos dataframes usando um DSL do tipo LINQ ou SparkSQL e depois gravar o resultado em arquivos, tabelas temporárias do Spark, alguns tipos de linguagem de programação ou console.
Transformar código .NET
A linguagem de expressão do U-SQL é C# e oferece várias maneiras de expandir o código .NET personalizado com funções definidas pelo usuário, operadores definidos pelo usuário e agregadores definidos pelo usuário.
O Azure Synapse e o Azure HDInsight Spark agora dão suporte nativo à execução de código .NET com .NET para Apache Spark. Isso significa que você pode reutilizar algumas ou todas as suas funções .NET definidas pelo usuário com o Spark. Observe que U-SQL usa o .NET Framework enquanto o .NET para Apache Spark é baseado no .NET Core 3.1 ou posterior.
Os UDOs (operadores definidos pelo usuário) do U-SQL estão usando o modelo de UDO do U-SQL para fornecer execução horizontal do código do operador. Assim, os UDOs precisarão ser reescritos em funções definidas pelo usuário para se ajustarem ao modelo de execução do Spark.
Atualmente, o .NET para Apache Spark não oferece suporte a agregadores definidos pelo usuário. Assim, os agregadores definidos pelo usuário do U-SQL precisarão ser traduzidos para agregadores definidos pelo usuário do Spark escritos em Scala.
Se não quiser aproveitar as vantagens dos recursos do .NET para Apache Spark, você terá que reescrever suas expressões em uma expressão, função, agregador ou conector equivalente do Spark, Scala, Java ou Python.
Em qualquer caso, se você tiver uma grande quantidade de lógica .NET dentro dos scripts U-SQL, entre em contato conosco por meio de seu representante de Conta da Microsoft para obter diretrizes adicionais.
Os detalhes a seguir são para os diferentes casos de usos de .NET e de C# em scripts U-SQL.
Transformar expressões escalares em linha C# do U-SQL
A linguagem de expressão do U-SQL é C#. Muitas das expressões U-SQL escalares embutidas são implementadas nativamente para melhorar o desempenho, enquanto expressões mais complexas podem ser executadas por meio de chamadas para a estrutura .NET.
O Spark tem sua própria linguagem de expressão escalar (como parte da DSL ou em SparkSQL) e permite chamar funções definidas pelo usuário escritas para o runtime Python, .NET ou JVM.
Se você tiver expressões escalares no U-SQL, primeiro encontre a expressão escalar do Spark mais apropriada, nativamente conhecida, para obter o máximo de desempenho, e depois mapeie as outras expressões para uma função definida pelo usuário, na linguagem de runtime Spark de sua escolha.
Lembre-se de que o .NET e o C# têm semântica de tipo diferente das do runtime JVM, Python e DSL do Spark. Confira abaixo para obter mais detalhes sobre as diferenças dos tipos de sistemas.
Transformar funções .NET escalares e agregadores definidos pelo usuário
O U-SQL fornece maneiras de chamar funções .NET escalares arbitrárias e chamar agregadores definidos pelo usuário escritos em .NET.
O Spark também suporta funções definidas pelo usuário e agregadores definidos pelo usuário, escritos na maioria de suas linguagens de hospedagem que podem ser chamadas a partir de DSL e SparkSQL do Spark.
Conforme mencionado acima, o .NET para Apache Spark oferece suporte a funções definidas pelo usuário escritas em .NET, mas não oferece suporte a agregadores definidos pelo usuário. Portanto, para funções definidas pelo usuário, o .NET para Apache Spark pode ser usado, enquanto os agregadores definidos pelo usuário precisam ser criados em Scala para Spark.
Transformar UDOs (Operadores Definidos pelo Usuário)
O U-SQL fornece várias categorias de UDOs (Operadores Definidos pelo Usuário), como extratores, saídas, redutores, processadores, aplicadores e combinadores que podem ser escritos em .NET (e, até certo ponto, em Python e R).
O Spark não oferece o mesmo modelo de extensibilidade para operadores, mas possui recursos equivalentes para alguns.
O equivalente do Spark para extratores e saídas são os conectores do Spark. Para muitos extratores U-SQL, você consegue encontrar um conector equivalente na comunidade virtual do Spark. Para outros, você terá que escrever um conector personalizado. Se o extrator U-SQL for complexo e usar várias bibliotecas .NET, é preferível criar um conector em Scala que usa a interoperabilidade para chamar a biblioteca .NET que faz o processamento dos dados. Nesse caso, você terá que implantar o tempo de execução do .NET Core no cluster Spark e certificar-se de que as bibliotecas .NET referenciadas sejam compatíveis com o .NET Standard 2.0.
Os outros tipos de UDOs do U-SQL precisam ser reescritos usando funções e agregadores definidos pelo usuário e a expressão DLS ou SparkSQL do Spark semanticamente adequada. Por exemplo, um processador pode ser mapeado para um SELECT de várias invocações UDF, empacotado como uma função que recebe um dataframe como argumento e retorna um dataframe.
Transformar bibliotecas opcionais do U-SQL
U-SQL fornece um conjunto de bibliotecas opcionais e de demonstração que oferecem Python, R, JSON, XML, suporte AVRO e alguns recursos de serviços IA do Azure.
O Spark tem sua própria integração Python e R, respectivamente pySpark e SparkR, e fornece conectores para ler e gravar JSON, XML e AVRO.
Se precisar transformar um script que faça referência às bibliotecas de serviços de IA do Azure, recomendamos que nos contacte através do seu representante de conta Microsoft.
Transformar valores digitados
Como o sistema de tipos do U-SQL é baseado no sistema de tipos .NET e o Spark tem seu próprio sistema de tipos que é afetado pela ligação da linguagem host, você terá que se certificar de que os tipos nos quais você está operando estão próximos e para determinados tipos , os intervalos de tipo, precisão e/ou escala podem ser ligeiramente diferentes. Além disso, o U-SQL e o Spark tratam valores null
de forma diferente.
Tipos de dados
A tabela a seguir fornece os tipos equivalentes em Spark, Scala e PySpark para os tipos de U-SQL fornecidos.
U-SQL | Spark | Scala | PySpark |
---|---|---|---|
byte |
|||
sbyte |
ByteType |
Byte |
ByteType |
int |
IntegerType |
Int |
IntegerType |
uint |
|||
long |
LongType |
Long |
LongType |
ulong |
|||
float |
FloatType |
Float |
FloatType |
double |
DoubleType |
Double |
DoubleType |
decimal |
DecimalType |
java.math.BigDecimal |
DecimalType |
short |
ShortType |
Short |
ShortType |
ushort |
|||
char |
Char |
||
string |
StringType |
String |
StringType |
DateTime |
DateType , TimestampType |
java.sql.Date , java.sql.Timestamp |
DateType , TimestampType |
bool |
BooleanType |
Boolean |
BooleanType |
Guid |
|||
byte[] |
BinaryType |
Array[Byte] |
BinaryType |
SQL.MAP<K,V> |
MapType(keyType, valueType, valueContainsNull) |
scala.collection.Map |
MapType(keyType, valueType, valueContainsNull=True) |
SQL.ARRAY<T> |
ArrayType(elementType, containsNull) |
scala.collection.Seq |
ArrayType(elementType, containsNull=True) |
Para saber mais, veja:
- org.apache.spark.sql.types
- Tipos de SQL e DataFrames do Spark
- Tipos de valor do Scala
- pyspark.sql.types
Tratamento de valores NULL
No Spark, por padrão, os tipos permitem valores nulos (NULL), mas no U-SQL, você marca explicitamente escalar, não objeto como podendo conter valor nulo. Embora o Spark permita que você defina uma coluna como não podendo conter valor nulo, ele não impede a restrição e pode levar a um resultado incorreto.
No Spark, o NULL (nulo) indica que o valor é desconhecido. Um valor NULL do Spark é diferente de qualquer outro valor, incluindo ele próprio. As comparações entre dois valores NULL do Spark, ou entre um valor NULL e qualquer outro valor, retornam desconhecido porque o valor de cada NULL é desconhecido.
Esse comportamento é diferente do U-SQL, que segue a semântica do C#, em que null
é diferente de qualquer outro valor, mas é igual a ele mesmo.
Portanto, uma instrução SELECT
do SparkSQL que usa WHERE column_name = NULL
, retorna zero linhas mesmo que haja valores NULL em column_name
, enquanto no U-SQL, ele retorna as linhas em que column_name
está definido como null
. Da mesma forma, uma instrução SELECT
do Spark que usa WHERE column_name != NULL
, retorna zero linhas mesmo que haja valores NULL em column_name
, enquanto no U-SQL, ele retorna as linhas que não têm NULL. Portanto, se você quer usar a semântica de verificação de NULL do U-SQL, use isnull e isnotnull respectivamente (ou seus equivalentes de DSL).
Transformar objetos do catálogo U-SQL
Uma grande diferença é que os scripts U-SQL podem usar seus objetos de catálogo, muitos dos quais não têm nenhum equivalente direto do Spark.
O Spark é compatível com os conceitos de Metastore do Hive, principalmente bancos de dados, tabelas e visões. Assim, você pode mapear bancos de dados e esquemas do U-SQL para bancos de dados Hive, e tabelas U-SQL para tabelas do Spark (consulte Movendo dados armazenados em tabelas U-SQL), mas não é compatível com TVFs (Funções com Valor de Tabela), procedimentos armazenados, assembly U-SQL, fontes de dados externas etc.
Os objetos de código do U-SQL, como exibições, TVFs, procedimentos armazenados e assembly, podem ser modelados por meio de funções de código e bibliotecas no Spark, e referenciados usando a função da linguagem hospedeira e os mecanismos de abstração procedural (por exemplo, por meio da importação de módulos Python ou referência a funções do Scala).
Se o catálogo do U-SQL foi usado para compartilhar dados e objetos de código entre projetos e equipes, os mecanismos equivalentes para compartilhamento precisam ser usados (por exemplo, Maven para compartilhar objetos de código).
Transformar expressões de conjunto de linhas U-SQL e expressões escalares baseadas em SQL
A linguagem principal do U-SQL está transformando conjuntos de linhas e baseia-se no SQL. A seguir está uma lista não exaustiva das expressões de conjunto de linhas mais comuns oferecidas no U-SQL:
SELECT
/FROM
/WHERE
/GROUP BY
+Agregações+HAVING
/ORDER BY
+FETCH
Expressões
INNER
/OUTER
/CROSS
/SEMI
JOIN
Expressões
CROSS
/OUTER
APPLY
Expressões
PIVOT
/UNPIVOT
Construtor de conjunto de linhas
VALUES
Expressões de agrupamento
UNION
/OUTER UNION
/INTERSECT
/EXCEPT
Além disso, o U-SQL fornece várias expressões escalares baseadas em SQL, como
- Expressões de janela
OVER
- vários agregadores integrados e funções de classificação (
SUM
,FIRST
etc.) - Algumas das expressões escalares do SQL mais conhecidas:
CASE
,LIKE
, (NOT
)IN
,AND
,OR
etc.
O Spark oferece expressões equivalentes nos formatos DSL e SparkSQL para a maioria dessas expressões. Algumas das expressões não suportadas nativamente no Spark precisam ser reescritas usando uma combinação das expressões nativas do Spark e padrões semanticamente equivalentes. Por exemplo, o OUTER UNION
precisa ser traduzido para a combinação equivalente de projeções e uniões.
Devido ao tratamento diferente de valores NULL, uma junção U-SQL sempre corresponderá a uma linha se ambas as colunas comparadas contiverem um valor NULL, enquanto uma junção no Spark não corresponderá a essas colunas, a menos que sejam adicionadas verificações nulas explícitas.
Transformar outros conceitos do U-SQL
U-SQL também oferece vários outros recursos e conceitos, como consultas federadas em bancos de dados SQL Server, parâmetros, variáveis de expressão escalar e lambda, variáveis de sistema, OPTION
dicas.
Consultas federadas em bancos de dados/tabelas externas do SQL Server
O U-SQL fornece a fonte de dados e as tabelas externas, bem como consultas diretas no Banco de Dados SQL do Azure. Embora o Spark não ofereça as mesmas abstrações de objeto, ele fornece o Conector Spark para Banco de Dados SQL do Azure que pode ser usado para consultar bancos de dados SQL.
Parâmetros e variáveis do U-SQL
Parâmetros e variáveis de usuário têm conceitos equivalentes no Spark e em suas linguagens de hospedagem.
Por exemplo, no Scala, você pode definir uma variável com a palavra-chave var
:
var x = 2 * 3;
println(x)
As variáveis de sistema do U-SQL (variáveis que começam com @@
) podem ser divididas em duas categorias:
- Variáveis de sistema configuráveis que podem ser definidas com valores específicos para afetar o comportamento dos scripts
- Variáveis de sistema informativas que consultam informações de nível de trabalho e de sistema
A maioria das variáveis de sistema configuráveis não tem equivalente direto no Spark. Algumas das variáveis de sistema informativas são modeladas passando as informações como argumentos durante a execução do trabalho. Outras podem ter uma função equivalente na linguagem de hospedagem do Spark.
Dicas do U-SQL
O U-SQL oferece várias maneiras sintáticas de fornecer dicas para o otimizador de consulta e o mecanismo de execução:
- definindo uma variável de sistema do U-SQL
- uma cláusula
OPTION
associada à expressão de conjunto de linhas para fornecer uma dica de dados ou de plano - uma dica de agregação na sintaxe da expressão de agregação (por exemplo,
BROADCASTLEFT
)
O otimizador de consulta baseado em custo do Spark tem seus próprios recursos para fornecer dicas e ajustar o desempenho da consulta. Consulte a documentação correspondente.
Próximas etapas
- Entender os formatos de dados do Spark para desenvolvedores de U-SQL
- .NET para Apache Spark
- Atualize suas soluções de big análise de dados do Azure Data Lake Storage Gen1 para o Azure Data Lake Storage Gen2
- Transformar dados usando a atividade do Spark no Azure Data Factory
- Transformar dados usando a atividade do Hive do Hadoop no Azure Data Factory
- O que é o Apache Spark no Azure HDInsight