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.

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:

  1. 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.
  2. 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.
  3. 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:

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