Compreender o código do Apache Spark para programadores de U-SQL

Importante

O Azure Data Lake Analytics descontinuado a 29 de fevereiro de 2024. Saiba mais com este anúncio.

Para análise de dados, a sua organização pode utilizar o Azure Synapse Analytics ou o Microsoft Fabric.

Esta secção fornece orientações de alto nível sobre a transformação de Scripts U-SQL no Apache Spark.

Compreender os paradigmas de processamento e linguagem U-SQL e 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 a SQL que utiliza um paradigma de fluxo de dados e permite-lhe incorporar e aumentar horizontalmente facilmente o código de utilizador escrito em .NET (por exemplo, C#), Python e R. As extensões de utilizador podem implementar expressões simples ou funções definidas pelo utilizador, mas também podem fornecer ao utilizador a capacidade de implementar os chamados operadores definidos pelo utilizador que implementam operadores personalizados para realizar transformações ao nível do conjunto de linhas, extrações e saídas de escrita.

O Spark é uma arquitetura de escalamento horizontal que oferece vários enlaces de linguagem em Scala, Java, Python, .NET, etc., onde escreve principalmente o código numa destas linguagens, cria abstrações de dados denominadas conjuntos de dados distribuídos resilientes (RDD), dataframes e conjuntos de dados e, em seguida, utiliza uma linguagem específica de domínio (DSL) semelhante ao LINQ para os transformar. Também fornece SparkSQL como uma sublanguage declarativa no dataframe e abstrações de conjuntos de dados. O 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 executa a transformação, mas sim a compilação do plano de execução que será submetido para avaliação com uma ação (por exemplo, escrever o resultado numa tabela ou ficheiro temporário ou imprimir o resultado).

Assim, ao traduzir um script U-SQL para um programa Spark, terá de decidir qual a linguagem que pretende utilizar para, pelo menos, gerar a abstração do pacote de dados (que é atualmente a abstração de dados utilizada com mais frequência) e se pretende escrever as transformações declarativas do fluxo de dados com o DSL ou o SparkSQL. Em alguns casos mais complexos, poderá ter de dividir o script U-SQL numa sequência do Spark e outros passos implementados com Azure Batch ou Funções do Azure.

Além disso, o Azure Data Lake Analytics oferece U-SQL num ambiente de serviço sem servidor onde os recursos são alocados para cada tarefa, enquanto Azure Synapse Spark, Azure Databricks e Azure HDInsight oferecem o Spark sob a forma de um serviço de cluster ou com os chamados modelos de conjunto do Spark. Ao transformar a sua aplicação, terá de ter em conta as implicações de agora criar, dimensionar, dimensionar e desativar os clusters ou conjuntos.

Transformar scripts U-SQL

Os scripts U-SQL seguem o seguinte padrão de processamento:

  1. Os dados são lidos a partir de ficheiros não estruturados, utilizando a EXTRACT instrução, uma especificação de localização ou conjunto de ficheiros e o extrator incorporado ou definido pelo utilizador e o esquema pretendido, ou a partir de tabelas U-SQL (tabelas geridas ou externas). É representado como um conjunto de linhas.
  2. Os conjuntos de linhas são transformados em múltiplas 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 exportados para ambos os ficheiros com a OUTPUT instrução que especifica as localizações e um outputter incorporado ou definido pelo utilizador, ou numa tabela U-SQL.

O script é avaliado preguiçosamente, o que significa que cada passo de extração e transformação é composto numa árvore de expressões e avaliado globalmente (o fluxo de dados).

Os programas Spark são semelhantes na medida em que utilizaria conectores do Spark para ler os dados e criar os dataframes e, em seguida, aplicar as transformações nos dataframes com o DSL ou SparkSQL semelhante ao LINQ e, em seguida, escrever o resultado em ficheiros, tabelas temporárias do Spark, alguns tipos de linguagem de programação ou na consola.

Transformar código .NET

A linguagem de expressão do U-SQL é C# e oferece várias formas de aumentar horizontalmente o código .NET personalizado com funções definidas pelo utilizador, operadores definidos pelo utilizador e agregadores definidos pelo utilizador.

Azure Synapse e o Azure HDInsight Spark suportam agora nativamente a execução de código .NET com .NET para Apache Spark. Isto significa que pode reutilizar potencialmente algumas ou todas as funções definidas pelo utilizador do .NET com o Spark. Tenha em atenção que o U-SQL utiliza o .NET Framework enquanto o .NET para Apache Spark se baseia no .NET Core 3.1 ou posterior.

Os operadores definidos pelo utilizador (UDOs) do U-SQL estão a utilizar o modelo U-SQL UDO para fornecer uma execução horizontal do código do operador. Assim, os UDOs terão de ser reescritos em funções definidas pelo utilizador para se ajustarem ao modelo de execução do Spark.

Atualmente, o .NET para Apache Spark não suporta agregadores definidos pelo utilizador. Assim, os agregadores definidos pelo utilizador U-SQL terão de ser traduzidos para agregadores definidos pelo utilizador do Spark escritos no Scala.

Se não quiser tirar partido das capacidades do .NET para Apache Spark, terá de reescrever as expressões para uma expressão equivalente do Spark, Scala, Java ou Python, função, agregador ou conector.

Em todo o caso, se tiver uma grande quantidade de lógica .NET nos scripts U-SQL, contacte-nos através do seu representante da Conta Microsoft para obter mais orientações.

Os seguintes detalhes destinam-se aos diferentes casos de utilização de .NET e C# em scripts U-SQL.

Transformar expressões C# U-SQL inline escalares

A linguagem de expressão do U-SQL é C#. Muitas das expressões U-SQL inline escalares são implementadas nativamente para melhorar o desempenho, enquanto expressões mais complexas podem ser executadas através da chamada para a arquitetura .NET.

O Spark tem a sua própria linguagem de expressão escalar (como parte do DSL ou no SparkSQL) e permite chamar funções definidas pelo utilizador escritas para o runtime JVM, .NET ou Python.

Se tiver expressões escalares no U-SQL, primeiro deve encontrar a expressão escalar do Spark mais adequada nativamente compreendida para obter o maior desempenho e, em seguida, mapear as outras expressões para uma função definida pelo utilizador da linguagem de runtime do Spark à sua escolha.

Tenha em atenção que .NET e C# têm semântica de tipo diferente dos runtimes JVM e Python e DSL do Spark. Veja abaixo para obter mais detalhes sobre as diferenças de sistema do tipo.

Transformar funções .NET escalares definidas pelo utilizador e agregadores definidos pelo utilizador

O U-SQL fornece formas de chamar funções .NET escalares arbitrárias e chamar agregadores definidos pelo utilizador escritos no .NET.

O Spark também oferece suporte para funções definidas pelo utilizador e agregadores definidos pelo utilizador escritos na maioria dos idiomas de alojamento que podem ser chamados a partir do DSL do Spark e do SparkSQL.

Conforme mencionado acima, o .NET para Apache Spark suporta funções definidas pelo utilizador escritas no .NET, mas não suporta agregadores definidos pelo utilizador. Assim, para funções definidas pelo utilizador, o .NET para Apache Spark pode ser utilizado, enquanto os agregadores definidos pelo utilizador têm de ser criados no Scala para Spark.

Transformar operadores definidos pelo utilizador (UDOs)

O U-SQL fornece várias categorias de operadores definidos pelo utilizador (UDOs), tais como extratores, outputters, redutores, processadores, aplicadores e combinadores que podem ser escritos em .NET (e, em certa medida, em Python e R).

O Spark não oferece o mesmo modelo de extensibilidade para operadores, mas tem capacidades equivalentes para alguns.

O equivalente do Spark aos extratores e saídas são os conectores do Spark. Para muitos extratores U-SQL, pode encontrar um conector equivalente na comunidade do Spark. Para outras pessoas, terá de escrever um conector personalizado. Se o extrator U-SQL for complexo e utilizar várias bibliotecas .NET, poderá ser preferível criar um conector no Scala que utilize o interop para chamar para a biblioteca .NET que faz o processamento real dos dados. Nesse caso, terá de implementar o runtime do .NET Core no cluster do Spark e certificar-se de que as bibliotecas .NET referenciadas estão em conformidade com o .NET Standard 2.0.

Os outros tipos de UDOs U-SQL terão de ser reescritos com funções e agregadores definidos pelo utilizador e a expressão spark DLS ou SparkSQL semanticamente adequada. Por exemplo, um processador pode ser mapeado para um SELECT de várias invocações UDF, empacotadas como uma função que utiliza um dataframe como um argumento e devolve um dataframe.

Transformar as bibliotecas opcionais do U-SQL

O U-SQL fornece um conjunto de bibliotecas opcionais e de demonstração que oferecem python, R, JSON, XML, suporte AVRO e algumas capacidades de serviços de IA do Azure.

O Spark oferece a sua própria integração python e R, pySpark e SparkR, respetivamente, e fornece conectores para ler e escrever JSON, XML e AVRO.

Se precisar de transformar um script que referencia as bibliotecas de serviços de IA do Azure, recomendamos que nos contacte através do seu representante da Conta Microsoft.

Transformar valores digitados

Uma vez que o sistema de tipo U-SQL se baseia no sistema de tipo .NET e o Spark tem um sistema de tipo próprio que é afetado pelo enlace de idioma do anfitrião, terá de se certificar de que os tipos em que está a operar estão próximos e, para determinados tipos, os intervalos de tipos, precisão e/ou escala podem ser ligeiramente diferentes. Além disso, o U-SQL e o Spark tratam null os valores de forma diferente.

Tipos de dados

A tabela seguinte fornece os tipos equivalentes no Spark, Scala e PySpark para os tipos de U-SQL especificados.

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 obter mais informações, consulte:

Tratamento de NULL

No Spark, os tipos por predefinição permitem valores NULL enquanto estão no U-SQL, pode marcar explicitamente escalar, não objeto como nulo. Embora o Spark lhe permita definir uma coluna como não anulável, não irá impor a restrição e poderá levar a um resultado errado.

No Spark, NULL indica que o valor é desconhecido. Um valor NULL do Spark é diferente de qualquer valor, incluindo o próprio. As comparações entre dois valores NULL do Spark ou entre um valor NULL e qualquer outro valor, devolvem desconhecido porque o valor de cada NULL é desconhecido.

Este comportamento é diferente do U-SQL, que segue a semântica C#, em null que é diferente de qualquer valor, mas igual a si próprio.

Assim, uma instrução SparkSQL que utiliza WHERE column_name = NULL devolve zero linhas, mesmo que existam valores NULL em column_name, enquanto no U-SQL, devolveria as linhas em column_name que está definida como null.SELECT Da mesma forma, uma instrução spark SELECT que utiliza WHERE column_name != NULL devolve zero linhas, mesmo que existam valores não nulos em column_name, enquanto no U-SQL, devolveria as linhas que não são nulas. Assim, se quiser a semântica de verificação nula U-SQL, deve utilizar isull e isnotnull , respetivamente (ou o respetivo equivalente DSL).

Transformar objetos do catálogo U-SQL

Uma grande diferença é que os Scripts U-SQL podem utilizar os respetivos objetos de catálogo, muitos dos quais não têm equivalentes diretos do Spark.

O Spark fornece suporte para os conceitos do Arquivo de Metas do Hive, principalmente bases de dados, tabelas e vistas, para que possa mapear bases de dados E esquemas U-SQL para bases de dados do Hive e tabelas U-SQL para tabelas do Spark (veja Mover dados armazenados em tabelas U-SQL), mas não tem suporte para funções de valor de tabela (TVFs), procedimentos armazenados, assemblagens U-SQL, origens de dados externas, etc.

Os objetos de código U-SQL, como vistas, TVFs, procedimentos armazenados e assemblagens, podem ser modelados através de funções de código e bibliotecas no Spark e referenciados através dos mecanismos de abstração de funções e procedimentos da linguagem anfitriã (por exemplo, através da importação de módulos Python ou da referência a funções Scala).

Se o catálogo U-SQL tiver sido utilizado para partilhar dados e objetos de código entre projetos e equipas, os mecanismos equivalentes de partilha têm de ser utilizados (por exemplo, o Maven para partilhar objetos de código).

Transformar expressões de conjuntos de linhas U-SQL e expressões escalares baseadas em SQL

A linguagem principal do U-SQL está a transformar conjuntos de linhas e baseia-se no SQL. Segue-se uma lista não atual das expressões de conjunto de linhas mais comuns oferecidas no U-SQL:

  • SELECT/FROM/WHERE/GROUP BY+Agregações+HAVING/ORDER BY+FETCH

  • INNER/OUTER/CROSS/SEMIJOIN expressões

  • CROSS/OUTERAPPLY expressões

  • PIVOT/UNPIVOT expressões

  • VALUES construtor de conjuntos de linhas

  • Definir expressões UNION/OUTER UNION/INTERSECT/EXCEPT

Além disso, o U-SQL fornece várias expressões escalares baseadas em SQL, como

  • OVER expressões de criação de janelas
  • vários agregadores incorporados e funções de classificação (SUM, FIRST etc.)
  • Algumas das expressões escalares SQL mais conhecidas: CASE, LIKE, (NOT) IN, AND, OR etc.

O Spark oferece expressões equivalentes no respetivo formato DSL e SparkSQL para a maioria destas expressões. Algumas das expressões não suportadas nativamente no Spark terão de ser reescritas através de uma combinação de expressões nativas do Spark e padrões semanticamente equivalentes. Por exemplo, OUTER UNION terá de ser traduzido para a combinação equivalente de projecções e uniões.

Devido ao processamento diferente de valores NULL, uma associação U-SQL corresponderá sempre a uma linha se ambas as colunas que estão a ser comparadas contiverem um valor NULL, enquanto uma associação no Spark não corresponderá a essas colunas, a menos que sejam adicionadas verificações nulas explícitas.

Transformar outros conceitos de U-SQL

O U-SQL também oferece várias outras funcionalidades e conceitos, como consultas federadas em bases de dados SQL Server, parâmetros, variáveis de expressão lambda e escalar, variáveis de sistema, OPTION sugestões.

Consultas Federadas em bases de dados de SQL Server/tabelas externas

O U-SQL fornece tabelas externas e de origem de dados, bem como consultas diretas na Base de Dados do SQL do Azure. Embora o Spark não ofereça as mesmas abstrações de objetos, fornece o conector spark para SQL do Azure Base de Dados que pode ser utilizada para consultar bases de dados SQL.

Parâmetros e variáveis U-SQL

Os parâmetros e as variáveis de utilizador têm conceitos equivalentes no Spark e nos respetivos idiomas de alojamento.

Por exemplo, no Scala, pode definir uma variável com a var palavra-chave:

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 de definições que podem ser definidas para valores específicos para afetar o comportamento dos scripts
  • Variáveis de sistema informativo que consultam informações sobre o sistema e o nível de trabalho

A maioria das variáveis de sistema settable não tem equivalente direto no Spark. Algumas das variáveis de sistema informativo podem ser modeladas ao transmitir as informações como argumentos durante a execução da tarefa, outras podem ter uma função equivalente no idioma de alojamento do Spark.

Sugestões de U-SQL

O U-SQL oferece várias formas sintáticas de fornecer sugestões ao otimizador de consultas e ao motor de execução:

  • Definir uma variável de sistema U-SQL
  • uma OPTION cláusula associada à expressão de conjunto de linhas para fornecer uma sugestão de plano ou dados
  • uma sugestão de associação na sintaxe da expressão de associação (por exemplo, BROADCASTLEFT)

O otimizador de consultas baseado em custos do Spark tem as suas próprias capacidades para fornecer sugestões e otimizar o desempenho da consulta. Veja a documentação correspondente.

Passos seguintes