Förstå Apache Spark-kod för U-SQL-utvecklare

Viktigt

Azure Data Lake Analytics tillbaka den 29 februari 2024. Läs mer med det här meddelandet.

För dataanalys kan din organisation använda Azure Synapse Analytics eller Microsoft Fabric.

Det här avsnittet innehåller vägledning på hög nivå om hur du omvandlar U-SQL-skript till Apache Spark.

Förstå språk- och bearbetningsparadigmerna U-SQL och Spark

Innan du börjar migrera Azure Data Lake Analytics U-SQL-skript till Spark är det bra att förstå de två systemens allmänna språk och bearbetningsfilosofi.

U-SQL är ett SQL-liknande deklarativt frågespråk som använder ett dataflödesparadigm och gör att du enkelt kan bädda in och skala ut användarkod skriven i .NET (till exempel C#), Python och R. Användartilläggen kan implementera enkla uttryck eller användardefinierade funktioner, men kan också ge användaren möjlighet att implementera så kallade användardefinierade operatorer som implementerar anpassade operatorer för att utföra transformeringar på raduppsättningsnivå, extrahering och skrivning av utdata.

Spark är ett skalbart ramverk som erbjuder flera språkbindningar i Scala, Java, Python, .NET osv. där du främst skriver din kod på något av dessa språk, skapar dataabstraktioner som kallas elastiska distribuerade datauppsättningar (RDD), dataramar och datauppsättningar och sedan använder ett LINQ-liknande domänspecifikt språk (DSL) för att transformera dem. Den tillhandahåller även SparkSQL som en deklarativ underspråk på dataramen och datauppsättningsabstraktioner. DSL innehåller två kategorier av åtgärder, transformeringar och åtgärder. Om du tillämpar transformeringar på dataabstraktionerna körs inte omvandlingen, utan bygger i stället upp körningsplanen som ska skickas för utvärdering med en åtgärd (till exempel att skriva resultatet till en tillfällig tabell eller fil eller skriva ut resultatet).

När du översätter ett U-SQL-skript till ett Spark-program måste du därför bestämma vilket språk du vill använda för att minst generera dataramsabstraktionen (som för närvarande är den mest använda dataabstraktionen) och om du vill skriva de deklarativa dataflödesomvandlingarna med hjälp av DSL eller SparkSQL. I vissa mer komplexa fall kan du behöva dela upp U-SQL-skriptet i en sekvens med Spark och andra steg som implementeras med Azure Batch eller Azure Functions.

Dessutom erbjuder Azure Data Lake Analytics U-SQL i en serverlös jobbtjänstmiljö där resurser allokeras för varje jobb, medan Azure Synapse Spark, Azure Databricks och Azure HDInsight erbjuder Spark antingen i form av en klustertjänst eller med så kallade Spark-poolmallar. När du transformerar ditt program måste du ta hänsyn till konsekvenserna av att nu skapa, ändra storlek, skala och inaktivera kluster eller pooler.

Transformera U-SQL-skript

U-SQL-skript följer följande bearbetningsmönster:

  1. Data läss antingen från ostrukturerade filer med hjälp av -instruktionen EXTRACT , en plats- eller filuppsättningsspecifikation och den inbyggda eller användardefinierade extraktorn och önskat schema, eller från U-SQL-tabeller (hanterade eller externa tabeller). Den representeras som en raduppsättning.
  2. Raduppsättningarna transformeras i flera U-SQL-uttryck som tillämpar U-SQL-uttryck på raduppsättningarna och skapar nya raduppsättningar.
  3. Slutligen matas de resulterande raduppsättningarna ut i filer med instruktionen OUTPUT som anger platser och en inbyggd eller användardefinierad utdata, eller till en U-SQL-tabell.

Skriptet utvärderas lazily, vilket innebär att varje extraherings- och transformeringssteg består av ett uttrycksträd och utvärderas globalt (dataflödet).

Spark-program liknar dem eftersom du skulle använda Spark-anslutningsappar för att läsa data och skapa dataramarna, tillämpa omvandlingarna på dataramarna med antingen LINQ-liknande DSL eller SparkSQL och sedan skriva resultatet i filer, tillfälliga Spark-tabeller, vissa typer av programmeringsspråk eller konsolen.

Transformera .NET-kod

U-SQL:s uttrycksspråk är C# och erbjuder olika sätt att skala ut anpassad .NET-kod med användardefinierade funktioner, användardefinierade operatorer och användardefinierade aggregeringar.

Azure Synapse och Azure HDInsight Spark stöder nu internt körning av .NET-kod med .NET för Apache Spark. Det innebär att du kan återanvända vissa eller alla av dina användardefinierade .NET-funktioner med Spark. Observera dock att U-SQL använder .NET Framework medan .NET för Apache Spark baseras på .NET Core 3.1 eller senare.

Användardefinierade U-SQL-operatorer (U-SQL UDO) använder U-SQL UDO-modellen för att tillhandahålla utskalad körning av operatorns kod. Därför måste UDF:er skrivas om till användardefinierade funktioner för att passa in i Spark-körningsmodellen.

.NET för Apache Spark stöder för närvarande inte användardefinierade aggregatorer. Därför måste användardefinierade U-SQL-aggregatorer översättas till användardefinierade Spark-aggregatorer skrivna i Scala.

Om du inte vill dra nytta av .NET för Apache Spark-funktionerna måste du skriva om dina uttryck till motsvarande Spark-, Scala-, Java- eller Python-uttryck, funktion, aggregator eller anslutningsapp.

Om du i alla fall har en stor mängd .NET-logik i dina U-SQL-skript kontaktar du oss via din Microsoft-kontorepresentant för ytterligare vägledning.

Följande information gäller för de olika fallen av .NET- och C#-användningar i U-SQL-skript.

Transformera infogade U-SQL C#-uttryck

U-SQL:s uttrycksspråk är C#. Många av de skalära infogade U-SQL-uttrycken implementeras internt för bättre prestanda, medan mer komplexa uttryck kan köras genom anrop till .NET-ramverket.

Spark har ett eget skalärt uttrycksspråk (antingen som en del av DSL eller i SparkSQL) och tillåter anrop till användardefinierade funktioner som skrivits för JVM-, .NET- eller Python-körningen.

Om du har skalära uttryck i U-SQL bör du först hitta det lämpligaste skaläruttrycket i Spark för att få bästa möjliga prestanda och sedan mappa de andra uttrycken till en användardefinierad funktion med valfritt Spark-körningsspråk.

Tänk på att .NET och C# har andra typer av semantik än JVM- och Python-körningarna och Sparks DSL. Se nedan för mer information om skillnader i typsystemet.

Transformera användardefinierade skalära .NET-funktioner och användardefinierade aggregeringar

U-SQL tillhandahåller sätt att anropa godtyckliga skalära .NET-funktioner och anropa användardefinierade aggregeringar som skrivits i .NET.

Spark har även stöd för användardefinierade funktioner och användardefinierade aggregatorer som skrivits på de flesta av dess värdspråk och som kan anropas från Sparks DSL och SparkSQL.

Som nämnts ovan stöder .NET för Apache Spark användardefinierade funktioner skrivna i .NET, men stöder inte användardefinierade aggregatorer. För användardefinierade funktioner kan .NET för Apache Spark användas, medan användardefinierade aggregeringar måste skrivas i Scala för Spark.

Transformera användardefinierade operatorer (UDF: er)

U-SQL innehåller flera kategorier av användardefinierade operatorer (UDF: er), till exempel extraktorer, utdata, reducerare, processorer, tillämpare och kombinationer som kan skrivas i .NET (och i viss utsträckning i Python och R).

Spark erbjuder inte samma utökningsmodell för operatörer, men har motsvarande funktioner för vissa.

Spark-motsvarigheten till extraktorer och utdata är Spark-anslutningsappar. För många U-SQL-extraktorer kan du hitta en motsvarande anslutningsapp i Spark-communityn. För andra måste du skriva en anpassad anslutningsapp. Om U-SQL-extraktorn är komplex och använder flera .NET-bibliotek kan det vara bättre att skapa en anslutningsapp i Scala som använder interop för att anropa .NET-biblioteket som utför den faktiska databearbetningen. I så fall måste du distribuera .NET Core-körningen till Spark-klustret och se till att de refererade .NET-biblioteken är .NET Standard 2.0-kompatibla.

De andra typerna av U-SQL-U-SQL-UDF:er måste skrivas om med hjälp av användardefinierade funktioner och aggregatorer och det semantiskt lämpliga Spark DLS- eller SparkSQL-uttrycket. En processor kan till exempel mappas till en SELECT för olika UDF-anrop, paketerade som en funktion som tar en dataram som argument och returnerar en dataram.

Transformera U-SQL:s valfria bibliotek

U-SQL tillhandahåller en uppsättning valfria bibliotek och demobibliotek som erbjuder Python-, R-, JSON-, XML-, AVRO-stöd och vissa Funktioner för Azure AI-tjänster.

Spark erbjuder sin egen Python- och R-integrering, pySpark respektive SparkR, och tillhandahåller anslutningsappar för att läsa och skriva JSON, XML och AVRO.

Om du behöver transformera ett skript som refererar till Azure AI-tjänstbiblioteken rekommenderar vi att du kontaktar oss via din Microsoft-kontorepresentant.

Transformera typifierade värden

Eftersom U-SQL:s typsystem baseras på .NET-typsystemet och Spark har ett eget typsystem som påverkas av värdspråkbindningen måste du se till att de typer som du arbetar på är nära och för vissa typer kan typintervallen, precisionen och/eller skalan skilja sig något åt. Dessutom behandlar null U-SQL och Spark värden på olika sätt.

Datatyper

Följande tabell innehåller motsvarande typer i Spark, Scala och PySpark för de angivna U-SQL-typerna.

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)

Mer information finns i:

Behandling av NULL

I Spark tillåter typer per standard NULL-värden medan du i U-SQL uttryckligen markerar skalärt, icke-objekt som nullbart. Även om Spark gör att du kan definiera en kolumn som icke nullbar, kommer den inte att tillämpa villkoret och kan leda till fel resultat.

I Spark anger NULL att värdet är okänt. Ett Spark NULL-värde skiljer sig från alla värden, inklusive sig självt. Jämförelser mellan två Spark NULL-värden, eller mellan ett NULL-värde och ett annat värde, returnerar okänt eftersom värdet för varje NULL är okänt.

Det här beteendet skiljer sig från U-SQL, som följer C#-semantiken där null skiljer sig från alla värden men lika med sig själv.

Därför returnerar en SparkSQL-instruktion som använder WHERE column_name = NULL noll rader även om det finns NULL-värden i column_name, medan den i U-SQL returnerar raderna där column_name har angetts till null.SELECT På samma sätt returnerar en Spark-instruktion SELECT som använder WHERE column_name != NULL noll rader även om det finns icke-null-värden i column_name, medan den i U-SQL returnerar de rader som inte har null. Om du vill ha semantiken U-SQL null-check bör du därför använda isull respektive isnotnull (eller deras DSL-motsvarighet).

Transformera U-SQL-katalogobjekt

En stor skillnad är att U-SQL-skript kan använda sina katalogobjekt, varav många inte har någon direkt Spark-motsvarighet.

Spark har stöd för Hive Meta Store-begrepp, främst databaser, tabeller och vyer, så du kan mappa U-SQL-databaser och scheman till Hive-databaser och U-SQL-tabeller till Spark-tabeller (se Flytta data som lagras i U-SQL-tabeller), men det har inget stöd för tabellvärdesfunktioner (TVF), lagrade procedurer, U-SQL-sammansättningar, externa datakällor osv.

U-SQL-kodobjekt som vyer, TVF:er, lagrade procedurer och sammansättningar kan modelleras via kodfunktioner och bibliotek i Spark och refereras till med hjälp av värdspråkets funktions- och procedurabstraktionsmekanismer (till exempel genom att importera Python-moduler eller referera till Scala-funktioner).

Om U-SQL-katalogen har använts för att dela data och kodobjekt mellan projekt och team måste motsvarande mekanismer för delning användas (till exempel Maven för att dela kodobjekt).

Transformera U-SQL-raduppsättningsuttryck och SQL-baserade skaläruttryck

U-SQL:s kärnspråk omvandlar raduppsättningar och baseras på SQL. Följande är en obefintlig lista över de vanligaste raduppsättningsuttrycken som erbjuds i U-SQL:

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

  • INNER/OUTER/CROSS/SEMIJOIN Uttryck

  • CROSS/OUTERAPPLY Uttryck

  • PIVOT/UNPIVOT Uttryck

  • VALUES raduppsättningskonstruktor

  • Ange uttryck UNION/OUTER UNION/INTERSECT/EXCEPT

Dessutom tillhandahåller U-SQL olika SQL-baserade skaläruttryck, till exempel

  • OVER fönsteruttryck
  • olika inbyggda aggregeringar och rangordningsfunktioner (SUMFIRSTosv.)
  • Några av de mest välbekanta sql-skaläruttrycken: CASE, LIKE, (NOT) IN, ANDosv OR .

Spark erbjuder motsvarande uttryck i både sin DSL- och SparkSQL-form för de flesta av dessa uttryck. Vissa av de uttryck som inte stöds internt i Spark måste skrivas om med hjälp av en kombination av inbyggda Spark-uttryck och semantiskt likvärdiga mönster. Till exempel OUTER UNION måste översättas till motsvarande kombination av prognoser och fackföreningar.

På grund av den olika hanteringen av NULL-värden matchar en U-SQL-koppling alltid en rad om båda kolumnerna som jämförs innehåller ett NULL-värde, medan en koppling i Spark inte matchar sådana kolumner om inte explicita null-kontroller läggs till.

Transformera andra U-SQL-begrepp

U-SQL erbjuder också olika andra funktioner och begrepp, till exempel federerade frågor mot SQL Server databaser, parametrar, skalär- och lambda-uttrycksvariabler, systemvariabler och OPTION tips.

Federerade frågor mot SQL Server databaser/externa tabeller

U-SQL tillhandahåller datakällor och externa tabeller samt direkta frågor mot Azure SQL Database. Spark erbjuder inte samma objektabstraktioner, men det tillhandahåller Spark-anslutningsprogram för Azure SQL Database som kan användas för att fråga SQL-databaser.

U-SQL-parametrar och variabler

Parametrar och användarvariabler har motsvarande begrepp i Spark och deras värdspråk.

I Scala kan du till exempel definiera en variabel med nyckelordet var :

var x = 2 * 3;
println(x)

U-SQL:s systemvariabler (variabler som börjar med @@) kan delas in i två kategorier:

  • Inställningsbara systemvariabler som kan ställas in på specifika värden för att påverka skriptbeteendet
  • Informationssystemvariabler som frågar efter information på system- och jobbnivå

De flesta av de uppsättningsbara systemvariablerna har ingen direkt motsvarighet i Spark. Vissa informationssystemvariabler kan modelleras genom att informationen skickas som argument under jobbkörningen, andra kan ha en motsvarande funktion i Sparks värdspråk.

U-SQL-tips

U-SQL erbjuder flera syntaktiska sätt att ge tips till frågeoptimeraren och körningsmotorn:

  • Ange en U-SQL-systemvariabel
  • en sats OPTION som är associerad med raduppsättningsuttrycket för att tillhandahålla en data- eller plantips
  • ett kopplingstips i syntaxen för kopplingsuttrycket (till exempel BROADCASTLEFT)

Sparks kostnadsbaserade frågeoptimerare har sina egna funktioner för att ge tips och finjustera frågeprestandan. Se motsvarande dokumentation.

Nästa steg