Descripción del código de Apache Spark para los desarrolladores de U-SQL

Importante

Azure Data Lake Analytics retiró el 29 de febrero de 2024. Más información sobre este anuncio.

Para el análisis de datos, su organización puede usar Azure Synapse Analytics o Microsoft Fabric.

En esta sección se proporcionan instrucciones generales sobre cómo transformar scripts de U-SQL en Apache Spark.

Descripción de los paradigmas de procesamiento y lenguaje de U-SQL y Spark

Antes de empezar a migrar los scripts de U-SQL de Azure Data Lake Analytics a Spark, es útil comprender el lenguaje general y las filosofías de procesamiento de los dos sistemas.

U-SQL es un lenguaje de consulta declarativo parecido a SQL que utiliza un paradigma de flujo de datos y permite insertar y escalar horizontalmente de forma sencilla el código de usuario escrito en .NET (por ejemplo, C#), Python y R. Las extensiones de usuario pueden implementar expresiones sencillas o funciones definidas por el usuario, pero también pueden proporcionar al usuario la capacidad de implementar los llamados operadores definidos por el usuario, que implementan operadores personalizados para realizar transformaciones de nivel de conjunto de filas, extracciones y escritura de salida.

Spark es un marco de escalado horizontal que ofrece varios enlaces de lenguaje en Scala, Java, Python, .NET, etc., donde el código se escribe principalmente en uno de estos lenguajes, se crean abstracciones de datos llamadas conjuntos de datos distribuidos resistentes (RDD), tramas de datos y conjuntos de datos y, después, se usa un lenguaje específico de dominio (DSL) parecido a LINQ para transformarlos. También proporciona SparkSQL como sublenguaje declarativo en las abstracciones de los conjuntos de datos y tramas de datos. El Lenguaje específico de dominio proporciona dos categorías de operaciones, transformaciones y acciones. La aplicación de transformaciones a las abstracciones de datos no ejecutará la transformación, sino que creará el plan de ejecución que se enviará para su evaluación con una acción (por ejemplo, escribir el resultado en una tabla o archivo temporal o imprimir el resultado).

Por lo tanto, al traducir un script U-SQL a un programa spark, tendrá que decidir qué lenguaje desea usar para generar al menos la abstracción de trama de datos (que actualmente es la abstracción de datos usada con más frecuencia) y si desea escribir las transformaciones de flujo de datos declarativas mediante DSL o SparkSQL. En algunos casos más complejos, es posible que tenga que dividir el script U-SQL en una secuencia de Spark y otros pasos implementados con Azure Batch o Azure Functions.

Además, Azure Data Lake Analytics ofrece U-SQL en un entorno de servicio de trabajo sin servidor donde se asignan recursos para cada trabajo, mientras que Azure Synapse Spark, Azure Databricks y Azure HDInsight ofrecen Spark en forma de servicio de clúster o con plantillas de grupo de Spark. Al transformar la aplicación, tendrá que tener en cuenta las implicaciones de crear, ajustar el tamaño, escalar y retirar los clústeres o grupos.

Transformación de scripts de U-SQL

Los scripts de U-SQL siguen el siguiente patrón de procesamiento:

  1. Los datos se leen desde archivos no estructurados, mediante la instrucción EXTRACT, una ubicación o una especificación del conjunto de archivos, el extractor integrado o definido por el usuario, y el esquema deseado, o bien desde las tablas U-SQL (tablas administradas o externas). Se representa como un conjunto de filas.
  2. Los conjuntos de filas se transforman en varias instrucciones de U-SQL que aplican expresiones de U-SQL a los conjuntos de filas y generan nuevos conjuntos de filas.
  3. Por último, los conjuntos de filas resultantes se envían a los dos archivos mediante la instrucción OUTPUT, que especifica las ubicaciones y un outputter integrado o definido por el usuario, o a una tabla de U-SQL.

El script se evalúa de forma diferida, lo que significa que cada paso de extracción y transformación se compone en un árbol de expresión y se evalúa globalmente (el flujo de datos).

Los programas de Spark son similares en cuanto a que se usarían conectores de Spark para leer los datos y crear las tramas de datos y, después, se aplicarían las transformaciones en las tramas de datos mediante DSL o SparkSQL de tipo LINQ, y luego se escribiría el resultado en archivos, tablas temporales de Spark, algunos tipos de lenguajes de programación o la consola.

Transformación de código .NET

El lenguaje de expresiones de U-SQL es C# y ofrece varias maneras de escalar horizontalmente código .NET personalizado con funciones definidas por el usuario, operadores definidos por el usuario y agregadores definidos por el usuario.

Azure Synapse y Azure HDInsight Spark ahora admiten de forma nativa la ejecución de código de .NET con .NET para Apache Spark. Esto significa que puede reutilizar algunas o todas las funciones definidas por el usuario de .NET con Spark. Tenga en cuenta que U-SQL usa .NET Framework, mientras que .NET para Apache Spark se basa en .NET Core 3.1 o versiones posteriores.

Los operadores definidos por el usuario (UDO) de U-SQL usan el modelo de UDO de U-SQL para proporcionar una ejecución escalada horizontalmente del código del operador. Por lo tanto, los UDO tendrán que volver a escribirse en funciones definidas por el usuario para ajustarse al modelo de ejecución de Spark.

.NET para Apache Spark actualmente no admite agregadores definidos por el usuario. Por lo tanto, los agregadores definidos por el usuario de U-SQL tendrán que traducirse a agregadores definidos por el usuario de Spark escritos en Scala.

Si no desea aprovechar las funcionalidades de .NET para Apache Spark, tendrá que volver a escribir las expresiones en una expresión de Spark, Scala, Java o Python equivalente, función, agregador o conector.

En cualquier caso, si tiene una gran cantidad de lógica .NET en los scripts de U-SQL, póngase en contacto con nosotros a través de su representante de cuenta de Microsoft para obtener más información.

Los detalles siguientes sirven para los distintos casos de uso de .NET y C# de los scripts de U-SQL.

Transformación de expresiones insertadas escalares de C# en U-SQL

El lenguaje de las expresiones de U-SQL es C#. Muchas de las expresiones U-SQL insertadas escalares se implementan de forma nativa para mejorar el rendimiento, mientras que las expresiones más complejas se pueden ejecutar mediante llamadas a .NET Framework.

Spark tiene su propio lenguaje de expresiones escalares (ya sea como parte de DSL o en SparkSQL) y permite llamar a funciones definidas por el usuario escritas para el runtime de JVM, .NET o Python.

Si tiene expresiones escalares en U-SQL, primero debe buscar la expresión escalar de Spark de forma nativa más adecuada para obtener el máximo rendimiento y, después, asignar las demás expresiones en una función definida por el usuario del lenguaje del runtime de Spark que prefiera.

Tenga en cuenta que .NET y C# tienen una semántica de tipos distinta que la de los runtimes de JVM y Python y que la del DSL de Spark. Vea a continuación para obtener más información sobre las diferencias del sistema de tipos.

Transformación de funciones .NET escalares definidas por el usuario y de agregadores definidos por el usuario

U-SQL proporciona maneras de llamar a funciones de .NET escalares arbitrarias y de llamar a agregadores definidos por el usuario escritos en .NET.

Spark también ofrece compatibilidad con funciones definidas por el usuario y agregadores definidos por el usuario escritos en la mayoría de lenguajes de hospedaje a los que se puede llamar desde el DSL de Spark y SparkSQL.

Como se mencionó anteriormente, .NET para Apache Spark admite funciones definidas por el usuario escritas en .NET, pero no admite agregadores definidos por el usuario. Por lo tanto, para las funciones definidas por el usuario, se puede usar .NET para Apache Spark, mientras que los agregadores definidos por el usuario deben crearse en Scala para Spark.

Transformación de operadores definidos por el usuario (UDO)

U-SQL proporciona varias categorías de operadores definidos por el usuario (UDO), como extractores, outputters, reductores, procesadores, aplicadores y combinadores que se pueden escribir en .NET (y, hasta cierto punto, en Python y R).

Spark no ofrece el mismo modelo de extensibilidad para los operadores, pero tiene funcionalidades equivalentes para algunas.

El equivalente de Spark a los extractores y outputters son los conectores de Spark. Para muchos extractores de U-SQL, se puede encontrar un conector equivalente en la comunidad de Spark. Para otros usuarios, tendrá que escribir un conector personalizado. Si el extractor de U-SQL es complejo y utiliza varias bibliotecas .NET, puede ser preferible compilar un conector en Scala que use la interoperabilidad para llamar a la biblioteca .NET que realiza el procesamiento real de los datos. En ese caso, tendrá que implementar el entorno de ejecución de .NET Core en el clúster de Spark y asegurarse de que las bibliotecas de .NET a las que se hace referencia son compatibles con .NET Standard 2.0.

El resto de tipos de UDO de U-SQL deberán volver a escribirse con funciones definidas por el usuario y agregadores, y la expresión DSL de Spark o SparkSQL semánticamente adecuada. Por ejemplo, un procesador se puede asignar a una instrucción SELECT de varias invocaciones UDF, empaquetadas como una función que toma un dataframe como argumento y devuelve un dataframe.

Transformación de bibliotecas de U-SQL opcionales

U-SQL proporciona un conjunto de bibliotecas opcionales y de demostración que ofrecen funcionalidades de Python, R, JSON, XML, AVRO y algunos servicios de Azure AI.

Spark ofrece su propia integración de Python y R, pySpark y SparkR, respectivamente, y proporciona conectores para leer y escribir JSON, XML y AVRO.

Si necesita transformar un script que haga referencia a las bibliotecas de servicios de Azure AI, se recomienda ponerse en contacto con nosotros a través de su representante de la cuenta Microsoft.

Transformación de valores de tipo

Dado que el sistema de tipos de U-SQL se basa en el sistema de tipos de .NET y Spark tiene su propio sistema de tipos que se ve afectado por el enlace de lenguaje host, tendrá que asegurarse de que los tipos en los que está trabajando están cerca y para determinados tipos, los intervalos de tipos, la precisión o la escala pueden ser ligeramente diferentes. Además, U-SQL y Spark tratan los valores null de manera distinta.

Tipos de datos

En la tabla siguiente se proporcionan los tipos equivalentes en Spark, Scala y PySpark para los 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 más información, consulte:

Tratamiento del valor NULL

En Spark, los tipos admiten valores NULL de forma predeterminada, mientras que en U-SQL, se marca explícitamente el valor escalar, que no es de objeto, como capaz de admitir un valor NULL. Aunque Spark permite definir que una columna no admita un valor NULL, no se aplicará la restricción y podría producir un resultado incorrecto.

En Spark, NULL indica que el valor es desconocido. Un valor NULL de Spark es diferente de cualquier valor, incluido el mismo valor. Las comparaciones entre dos valores NULL de Spark, o entre un valor NULL y cualquier otro valor, devuelven un resultado desconocido porque el valor de cada NULL es desconocido.

Este comportamiento es diferente de U-SQL, que sigue la semántica de C#, donde null es diferente de cualquier valor, pero es igual a sí mismo.

Por tanto, una instrucción SELECT de SparkSQL que usa WHERE column_name = NULL devuelve cero filas aunque haya valores NULL en column_name, mientras que en U-SQL, devolvería las filas en las que el elemento column_name está establecido en null. De igual forma, una instrucción SELECT de Spark que usa WHERE column_name != NULL devuelve cero filas aunque haya valores que no sean NULL en column_name, mientras que en U-SQL, devolvería las filas cuyo valor no sea NULL. Por tanto, si quiere la semántica de comprobación de valores NULL de U-SQL, debe usar isnull e isnotnull respectivamente (o su equivalente de DSL).

Transformación de objetos de catálogo de U-SQL

Una diferencia importante es que los scripts de U-SQL pueden utilizar sus objetos de catálogo, muchos de los cuales no tienen ningún equivalente de Spark directo.

Spark proporciona compatibilidad con los conceptos de metastore de Hive, principalmente las bases de datos, tablas y vistas, por lo que se pueden asignar esquemas y bases de datos de U-SQL a bases de datos de Hive, y tablas de U-SQL a tablas de Spark (vea Traslado de los datos almacenados en tablas U-SQL), pero no admite funciones con valores de tabla (TVF), procedimientos almacenados, ensamblados de U-SQL, orígenes de datos externos, etc.

Los objetos de código de U-SQL, como vistas, TVF, procedimientos almacenados y ensamblados, se pueden modelar a través de las funciones de código y las bibliotecas de Spark, y se puede hacer referencia a ellos mediante la función del lenguaje de host y los mecanismos de abstracción de procedimientos (por ejemplo, mediante la importación de módulos de Python o haciendo referencia a funciones de Scala).

Si el catálogo de U-SQL se ha usado para compartir datos y objetos de código entre proyectos y equipos, se deben usar mecanismos equivalentes para compartir (por ejemplo, Maven para objetos de código de uso compartido).

Transformación de expresiones de conjunto de filas de U-SQL y expresiones escalares basadas en SQL

El lenguaje principal de U-SQL está transformando los conjuntos de filas y se basa en SQL. A continuación se muestra una lista no exhaustiva de las expresiones de conjunto de filas más comunes que se ofrecen en U-SQL:

  • SELECT/FROM/WHERE/GROUP BY+Aggregates+HAVING/ORDER BY+FETCH

  • Expresiones JOININNER/OUTER/CROSS/SEMI

  • Expresiones APPLYCROSS/OUTER

  • Expresiones PIVOT/UNPIVOT

  • Constructor de conjunto de filas VALUES

  • Expresiones de conjunto UNION/OUTER UNION/INTERSECT/EXCEPT

Además, U-SQL proporciona varias expresiones escalares basadas en SQL, como

  • expresiones OVER basadas en ventanas
  • varios agregadores integrados y funciones de clasificación (SUM, FIRST etc.)
  • Aquí se muestran algunas de las expresiones SQL escalares más conocidas: CASE, LIKE, (NOT) IN, AND, OR, etc.

Spark ofrece expresiones equivalentes en formato DSL y SparkSQL para la mayoría de estas expresiones. Algunas de las expresiones que no se admiten de forma nativa en Spark tendrán que reescribirse mediante una combinación de expresiones de Spark nativas y los patrones semánticamente equivalentes. Por ejemplo, OUTER UNION tendrá que traducirse en la combinación equivalente de proyecciones y uniones.

Debido al control diferente de los valores NULL, una combinación U-SQL siempre coincidirá con una fila si ambas columnas que se comparan contienen un valor NULL, mientras que una combinación en Spark no coincidirá con estas columnas a menos que se agreguen comprobaciones explícitas de valores NULL.

Transformación de otros conceptos de U-SQL

U-SQL también ofrece otras características y conceptos, como consultas federadas en bases de datos de SQL Server, parámetros, variables escalares y variables de expresión lambda, variables del sistema, OPTION sugerencias.

Consultas federadas en bases de datos o tablas externas de SQL Server

U-SQL proporciona tablas externas y de origen de datos, así como consultas directas en Azure SQL Database. Aunque Spark no ofrece las mismas abstracciones de objetos, proporciona el conector de Spark para Azure SQL Database que se puede usar para consultar bases de datos SQL.

Parámetros y variables de U-SQL

Los parámetros y las variables de usuario tienen conceptos equivalentes en Spark y sus lenguajes de hospedaje.

En Scala, por ejemplo, se puede definir una variable con la palabra clave var:

var x = 2 * 3;
println(x)

Las variables del sistema de U-SQL (variables que empiezan por @@) se pueden dividir en dos categorías:

  • Variables del sistema configurables que se pueden establecer en valores específicos para afectar al comportamiento de los scripts.
  • Variables del sistema informativas que consultan información de nivel de trabajo y de sistema.

La mayoría de variables del sistema configurables no tienen ningún equivalente directo en Spark. Algunas de las variables del sistema informativas se pueden modelar pasando la información como argumentos durante la ejecución del trabajo, mientras que otras pueden tener una función equivalente en el lenguaje de hospedaje de Spark.

Sugerencias de U-SQL

U-SQL ofrece varias maneras sintácticas de proporcionar sugerencias al optimizador de consultas y al motor de ejecución:

  • Establecer una variable del sistema de U-SQL.
  • Una cláusula OPTION asociada a la expresión de conjunto de filas para proporcionar una sugerencia de datos o de plan.
  • Una sugerencia de combinación en la sintaxis de la expresión de combinación (por ejemplo, BROADCASTLEFT).

El optimizador de consultas basado en el costo de Spark tiene sus propias funciones para proporcionar sugerencias y ajustar el rendimiento de las consultas. Consulte la documentación correspondiente.

Pasos siguientes