Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Belangrijk
Azure Data Lake Analytics is op 29 februari 2024 buiten gebruik gesteld. Meer informatie vindt u in deze aankondiging.
Voor gegevensanalyse kan uw organisatie Azure Synapse Analytics of Microsoft Fabric gebruiken.
U-SQL is een querytaal die is ontworpen voor het type big data van workloads. Een van de unieke functies van U-SQL is de combinatie van de declaratieve taal zoals SQL met de uitbreidbaarheid en programmeerbaarheid die wordt geleverd door C#. In deze handleiding concentreren we ons op de uitbreidbaarheid en programmeerbaarheid van de U-SQL-taal die is ingeschakeld door C#.
Behoeften
Download en installeer Azure Data Lake Tools voor Visual Studio.
Aan de slag met U-SQL
Bekijk het volgende U-SQL-script:
@a =
SELECT * FROM
(VALUES
("Contoso", 1500.0, "2017-03-39"),
("Woodgrove", 2700.0, "2017-04-10")
) AS D( customer, amount, date );
@results =
SELECT
customer,
amount,
date
FROM @a;
Dit script definieert twee RowSets: @a en @results. RowSet @results is gedefinieerd vanuit @a.
C#-typen en -expressies in U-SQL-script
Een U-SQL-expressie is een C#-expressie in combinatie met logische U-SQL-bewerkingen, zoals AND, ORen NOT. U-SQL-expressies kunnen worden gebruikt met SELECT, EXTRACT, WHERE, HAVING, GROUP BY en DECLARE. Met het volgende script wordt bijvoorbeeld een tekenreeks geparseerd als een Datum/tijd-waarde.
@results =
SELECT
customer,
amount,
DateTime.Parse(date) AS date
FROM @a;
Met het volgende codefragment wordt een tekenreeks geparseerd als datum/tijd-waarde in een DECLARE-instructie.
DECLARE @d = DateTime.Parse("2016/01/01");
C#-expressies gebruiken voor conversies van gegevenstypen
In het volgende voorbeeld ziet u hoe u een datum/tijd-gegevensconversie kunt uitvoeren met behulp van C#-expressies. In dit specifieke scenario worden datum/tijd-gegevens van tekenreeksen geconverteerd naar standaard datum/tijd met middernacht 00:00:00 tijdnotatie.
DECLARE @dt = "2016-07-06 10:23:15";
@rs1 =
SELECT
Convert.ToDateTime(Convert.ToDateTime(@dt).ToString("yyyy-MM-dd")) AS dt,
dt AS olddt
FROM @rs0;
OUTPUT @rs1
TO @output_file
USING Outputters.Text();
C#-expressies gebruiken voor de datum van vandaag
Als u de datum van vandaag wilt ophalen, kunt u de volgende C#-expressie gebruiken: DateTime.Now.ToString("M/d/yyyy")
Hier volgt een voorbeeld van het gebruik van deze expressie in een script:
@rs1 =
SELECT
MAX(guid) AS start_id,
MIN(dt) AS start_time,
MIN(Convert.ToDateTime(Convert.ToDateTime(dt<@default_dt?@default_dt:dt).ToString("yyyy-MM-dd"))) AS start_zero_time,
MIN(USQL_Programmability.CustomFunctions.GetFiscalPeriod(dt)) AS start_fiscalperiod,
DateTime.Now.ToString("M/d/yyyy") AS Nowdate,
user,
des
FROM @rs0
GROUP BY user, des;
.NET-assemblies gebruiken
Het uitbreidbaarheidsmodel van U-SQL is sterk afhankelijk van de mogelijkheid om aangepaste code toe te voegen vanuit .NET-assembly's.
Een .NET-assembly registreren
Gebruik de CREATE ASSEMBLY instructie om een .NET-assembly in een U-SQL Database te plaatsen. Daarna kunnen U-SQL-scripts deze assembly's gebruiken met behulp van de REFERENCE ASSEMBLY instructie.
De volgende code laat zien hoe u een assembly registreert:
CREATE ASSEMBLY MyDB.[MyAssembly]
FROM "/myassembly.dll";
De volgende code laat zien hoe u naar een assembly verwijst:
REFERENCE ASSEMBLY MyDB.[MyAssembly];
Raadpleeg de registratie-instructies voor assembly's die dit onderwerp in meer detail bespreken.
Assemblyversiebeheer gebruiken
Momenteel maakt U-SQL gebruik van .NET Framework versie 4.7.2. Zorg er dus voor dat uw eigen assembly's compatibel zijn met die versie van de runtime.
Zoals eerder vermeld, voert U-SQL code uit in een 64-bits (x64)-indeling. Zorg er dus voor dat uw code is gecompileerd om te worden uitgevoerd op x64. Anders krijg je de onjuiste formatfout die eerder is getoond.
Elk geüploade assembly-DLL en resourcebestand, zoals een andere runtime, een systeemeigen assembly of een configuratiebestand, kunnen maximaal 400 MB zijn. De totale grootte van ingezette resources, door middel van DEPLOY RESOURCE of door middel van verwijzingen naar assembly's en hun andere bestanden, mag niet groter zijn dan 3 GB.
Ten slotte kan elke U-SQL-database slechts één versie van een bepaalde assembly bevatten. Als u bijvoorbeeld zowel versie 7 als versie 8 van de NewtonSoft Json.NET-bibliotheek nodig hebt, moet u deze registreren in twee verschillende databases. Bovendien kan elk script slechts verwijzen naar één versie van een bepaalde assembly-DLL. In dit opzicht volgt U-SQL de Semantiek voor C#-assemblybeheer en versiebeheer.
Door de gebruiker gedefinieerde functies gebruiken: UDF
Door de gebruiker gedefinieerde U-SQL-functies of UDF zijn programmeerroutines die parameters accepteren, een actie uitvoeren (zoals een complexe berekening) en het resultaat van die actie retourneren als een waarde. De retourwaarde van UDF kan slechts één scalaire waarde zijn. U-SQL UDF kan worden aangeroepen in een U-SQL-basisscript zoals elke andere scalaire C#-functie.
U wordt aangeraden door de gebruiker gedefinieerde U-SQL-functies als openbaar en statisch te initialiseren.
public static string MyFunction(string param1)
{
return "my result";
}
Laten we eerst eens kijken naar het eenvoudige voorbeeld van het maken van een UDF.
In dit gebruiksscenario moeten we de fiscale periode bepalen, inclusief het fiscale kwartaal en de fiscale maand van de eerste login voor de betreffende gebruiker. De eerste fiscale maand van het jaar in ons scenario is juni.
Voor het berekenen van de fiscale periode introduceren we de volgende C#-functie:
public static string GetFiscalPeriod(DateTime dt)
{
int FiscalMonth=0;
if (dt.Month < 7)
{
FiscalMonth = dt.Month + 6;
}
else
{
FiscalMonth = dt.Month - 6;
}
int FiscalQuarter=0;
if (FiscalMonth >=1 && FiscalMonth<=3)
{
FiscalQuarter = 1;
}
if (FiscalMonth >= 4 && FiscalMonth <= 6)
{
FiscalQuarter = 2;
}
if (FiscalMonth >= 7 && FiscalMonth <= 9)
{
FiscalQuarter = 3;
}
if (FiscalMonth >= 10 && FiscalMonth <= 12)
{
FiscalQuarter = 4;
}
return "Q" + FiscalQuarter.ToString() + ":P" + FiscalMonth.ToString();
}
Het berekent gewoon fiscale maand en kwartaal en retourneert een tekenreekswaarde. Voor juni, de eerste maand van het eerste fiscale kwartaal, gebruiken we 'Q1:P1'. Voor juli gebruiken we 'Q1:P2', enzovoort.
Dit is een reguliere C#-functie die we gaan gebruiken in ons U-SQL-project.
In dit scenario ziet de sectie code-behind er als volgt uit:
using Microsoft.Analytics.Interfaces;
using Microsoft.Analytics.Types.Sql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace USQL_Programmability
{
public class CustomFunctions
{
public static string GetFiscalPeriod(DateTime dt)
{
int FiscalMonth=0;
if (dt.Month < 7)
{
FiscalMonth = dt.Month + 6;
}
else
{
FiscalMonth = dt.Month - 6;
}
int FiscalQuarter=0;
if (FiscalMonth >=1 && FiscalMonth<=3)
{
FiscalQuarter = 1;
}
if (FiscalMonth >= 4 && FiscalMonth <= 6)
{
FiscalQuarter = 2;
}
if (FiscalMonth >= 7 && FiscalMonth <= 9)
{
FiscalQuarter = 3;
}
if (FiscalMonth >= 10 && FiscalMonth <= 12)
{
FiscalQuarter = 4;
}
return "Q" + FiscalQuarter.ToString() + ":" + FiscalMonth.ToString();
}
}
}
Nu gaan we deze functie aanroepen vanuit het U-SQL-basisscript. Hiervoor moeten we een volledig gekwalificeerde naam opgeven voor de functie, inclusief de naamruimte, die in dit geval NameSpace.Class.Function(parameter) is.
USQL_Programmability.CustomFunctions.GetFiscalPeriod(dt)
Hier volgt het werkelijke U-SQL-basisscript:
DECLARE @input_file string = @"\usql-programmability\input_file.tsv";
DECLARE @output_file string = @"\usql-programmability\output_file.tsv";
@rs0 =
EXTRACT
guid Guid,
dt DateTime,
user String,
des String
FROM @input_file USING Extractors.Tsv();
DECLARE @default_dt DateTime = Convert.ToDateTime("06/01/2016");
@rs1 =
SELECT
MAX(guid) AS start_id,
MIN(dt) AS start_time,
MIN(Convert.ToDateTime(Convert.ToDateTime(dt<@default_dt?@default_dt:dt).ToString("yyyy-MM-dd"))) AS start_zero_time,
MIN(USQL_Programmability.CustomFunctions.GetFiscalPeriod(dt)) AS start_fiscalperiod,
user,
des
FROM @rs0
GROUP BY user, des;
OUTPUT @rs1
TO @output_file
USING Outputters.Text();
Hier volgt het uitvoerbestand van de scriptuitvoering:
0d8b9630-d5ca-11e5-8329-251efa3a2941,2016-02-11T07:04:17.2630000-08:00,2016-06-01T00:00:00.0000000,"Q3:8","User1",""
20843640-d771-11e5-b87b-8b7265c75a44,2016-02-11T07:04:17.2630000-08:00,2016-06-01T00:00:00.0000000,"Q3:8","User2",""
301f23d2-d690-11e5-9a98-4b4f60a1836f,2016-02-11T09:01:33.9720000-08:00,2016-06-01T00:00:00.0000000,"Q3:8","User3",""
In dit voorbeeld ziet u een eenvoudig gebruik van inline-UDF in U-SQL.
Status behouden tussen UDF-aanroepen
U-SQL C#-programmeerobjecten kunnen geavanceerder zijn, waarbij gebruik wordt gemaakt van interactiviteit via de globale variabelen achter de code. Laten we eens kijken naar het volgende zakelijke gebruiksscenario.
In grote organisaties kunnen gebruikers schakelen tussen variëteiten van interne toepassingen. Dit kunnen Microsoft Dynamics CRM, Power BI enzovoort zijn. Klanten willen mogelijk een telemetrieanalyse toepassen van hoe gebruikers schakelen tussen verschillende toepassingen, wat de gebruikstrends zijn, enzovoort. Het doel van het bedrijf is om het gebruik van toepassingen te optimaliseren. Ze willen mogelijk ook verschillende toepassingen of specifieke aanmeldingsroutines combineren.
Om dit doel te bereiken, moeten we sessie-id's en vertraging bepalen tussen de voorgaande sessie en de laatste sessie.
We moeten een eerdere aanmelding vinden en deze aanmelding vervolgens toewijzen aan alle sessies die worden gegenereerd voor dezelfde toepassing. De eerste uitdaging is dat u-SQL-basisscript niet toestaat om berekeningen toe te passen op al berekende kolommen met lag-functie. De tweede uitdaging is dat we de specifieke sessie voor alle sessies binnen dezelfde periode moeten houden.
Om dit probleem op te lossen, gebruiken we een globale variabele in een sectie achter code: static public string globalSession;.
Deze globale variabele wordt toegepast op de hele rijenset tijdens het uitvoeren van het script.
Dit is de code-behind-sectie van ons U-SQL-programma:
using Microsoft.Analytics.Interfaces;
using Microsoft.Analytics.Types.Sql;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace USQLApplication21
{
public class UserSession
{
static public string globalSession;
static public string StampUserSession(string eventTime, string PreviousRow, string Session)
{
if (!string.IsNullOrEmpty(PreviousRow))
{
double timeGap = Convert.ToDateTime(eventTime).Subtract(Convert.ToDateTime(PreviousRow)).TotalMinutes;
if (timeGap <= 60) {return Session;}
else {return Guid.NewGuid().ToString();}
}
else {return Guid.NewGuid().ToString();}
}
static public string getStampUserSession(string Session)
{
if (Session != globalSession && !string.IsNullOrEmpty(Session)) { globalSession = Session; }
return globalSession;
}
}
}
In dit voorbeeld ziet u de globale variabele static public string globalSession; die in de getStampUserSession functie wordt gebruikt en telkens wanneer de parameter Sessie wordt gewijzigd, opnieuw wordt geïnitialiseerd.
Het U-SQL-basisscript is als volgt:
DECLARE @in string = @"\UserSession\test1.tsv";
DECLARE @out1 string = @"\UserSession\Out1.csv";
DECLARE @out2 string = @"\UserSession\Out2.csv";
DECLARE @out3 string = @"\UserSession\Out3.csv";
@records =
EXTRACT DataId string,
EventDateTime string,
UserName string,
UserSessionTimestamp string
FROM @in
USING Extractors.Tsv();
@rs1 =
SELECT
EventDateTime,
UserName,
LAG(EventDateTime, 1)
OVER(PARTITION BY UserName ORDER BY EventDateTime ASC) AS prevDateTime,
string.IsNullOrEmpty(LAG(EventDateTime, 1)
OVER(PARTITION BY UserName ORDER BY EventDateTime ASC)) AS Flag,
USQLApplication21.UserSession.StampUserSession
(
EventDateTime,
LAG(EventDateTime, 1) OVER(PARTITION BY UserName ORDER BY EventDateTime ASC),
LAG(UserSessionTimestamp, 1) OVER(PARTITION BY UserName ORDER BY EventDateTime ASC)
) AS UserSessionTimestamp
FROM @records;
@rs2 =
SELECT
EventDateTime,
UserName,
LAG(EventDateTime, 1)
OVER(PARTITION BY UserName ORDER BY EventDateTime ASC) AS prevDateTime,
string.IsNullOrEmpty( LAG(EventDateTime, 1) OVER(PARTITION BY UserName ORDER BY EventDateTime ASC)) AS Flag,
USQLApplication21.UserSession.getStampUserSession(UserSessionTimestamp) AS UserSessionTimestamp
FROM @rs1
WHERE UserName != "UserName";
OUTPUT @rs2
TO @out2
ORDER BY UserName, EventDateTime ASC
USING Outputters.Csv();
De functie USQLApplication21.UserSession.getStampUserSession(UserSessionTimestamp) wordt hier aangeroepen tijdens de tweede berekening van de geheugenrijset. Het gaat langs de UserSessionTimestamp kolom en retourneert de waarde totdat UserSessionTimestamp is gewijzigd.
Het uitvoerbestand is als volgt:
"2016-02-19T07:32:36.8420000-08:00","User1",,True,"72a0660e-22df-428e-b672-e0977007177f"
"2016-02-17T11:52:43.6350000-08:00","User2",,True,"4a0cd19a-6e67-4d95-a119-4eda590226ba"
"2016-02-17T11:59:08.8320000-08:00","User2","2016-02-17T11:52:43.6350000-08:00",False,"4a0cd19a-6e67-4d95-a119-4eda590226ba"
"2016-02-11T07:04:17.2630000-08:00","User3",,True,"51860a7a-1610-4f74-a9ea-69d5eef7cd9c"
"2016-02-11T07:10:33.9720000-08:00","User3","2016-02-11T07:04:17.2630000-08:00",False,"51860a7a-1610-4f74-a9ea-69d5eef7cd9c"
"2016-02-15T21:27:41.8210000-08:00","User3","2016-02-11T07:10:33.9720000-08:00",False,"4d2bc48d-bdf3-4591-a9c1-7b15ceb8e074"
"2016-02-16T05:48:49.6360000-08:00","User3","2016-02-15T21:27:41.8210000-08:00",False,"dd3006d0-2dcd-42d0-b3a2-bc03dd77c8b9"
"2016-02-16T06:22:43.6390000-08:00","User3","2016-02-16T05:48:49.6360000-08:00",False,"dd3006d0-2dcd-42d0-b3a2-bc03dd77c8b9"
"2016-02-17T16:29:53.2280000-08:00","User3","2016-02-16T06:22:43.6390000-08:00",False,"2fa899c7-eecf-4b1b-a8cd-30c5357b4f3a"
"2016-02-17T16:39:07.2430000-08:00","User3","2016-02-17T16:29:53.2280000-08:00",False,"2fa899c7-eecf-4b1b-a8cd-30c5357b4f3a"
"2016-02-17T17:20:39.3220000-08:00","User3","2016-02-17T16:39:07.2430000-08:00",False,"2fa899c7-eecf-4b1b-a8cd-30c5357b4f3a"
"2016-02-19T05:23:54.5710000-08:00","User3","2016-02-17T17:20:39.3220000-08:00",False,"6ca7ed80-c149-4c22-b24b-94ff5b0d824d"
"2016-02-19T05:48:37.7510000-08:00","User3","2016-02-19T05:23:54.5710000-08:00",False,"6ca7ed80-c149-4c22-b24b-94ff5b0d824d"
"2016-02-19T06:40:27.4830000-08:00","User3","2016-02-19T05:48:37.7510000-08:00",False,"6ca7ed80-c149-4c22-b24b-94ff5b0d824d"
"2016-02-19T07:27:37.7550000-08:00","User3","2016-02-19T06:40:27.4830000-08:00",False,"6ca7ed80-c149-4c22-b24b-94ff5b0d824d"
"2016-02-19T19:35:40.9450000-08:00","User3","2016-02-19T07:27:37.7550000-08:00",False,"3f385f0b-3e68-4456-ac74-ff6cef093674"
"2016-02-20T00:07:37.8250000-08:00","User3","2016-02-19T19:35:40.9450000-08:00",False,"685f76d5-ca48-4c58-b77d-bd3a9ddb33da"
"2016-02-11T09:01:33.9720000-08:00","User4",,True,"9f0cf696-c8ba-449a-8d5f-1ca6ed8f2ee8"
"2016-02-17T06:30:38.6210000-08:00","User4","2016-02-11T09:01:33.9720000-08:00",False,"8b11fd2a-01bf-4a5e-a9af-3c92c4e4382a"
"2016-02-17T22:15:26.4020000-08:00","User4","2016-02-17T06:30:38.6210000-08:00",False,"4e1cb707-3b5f-49c1-90c7-9b33b86ca1f4"
"2016-02-18T14:37:27.6560000-08:00","User4","2016-02-17T22:15:26.4020000-08:00",False,"f4e44400-e837-40ed-8dfd-2ea264d4e338"
"2016-02-19T01:20:31.4800000-08:00","User4","2016-02-18T14:37:27.6560000-08:00",False,"2136f4cf-7c7d-43c1-8ae2-08f4ad6a6e08"
In dit voorbeeld ziet u een gecompliceerder use-casescenario waarin we een globale variabele gebruiken in een code-behind-sectie die wordt toegepast op de volledige geheugenrijset.