A U-SQL programozhatósági útmutatója – áttekintés
Fontos
Az Azure Data Lake Analytics 2024. február 29-én megszűnt. További információ ezzel a bejelentéssel.
Az adatelemzéshez a szervezet használhatja a Azure Synapse Analyticset vagy a Microsoft Fabricet.
Az U-SQL egy lekérdezési nyelv, amelyet big data típusú számítási feladatokhoz terveztek. Az U-SQL egyik egyedi jellemzője az SQL-szerű deklaratív nyelv és a C# által biztosított bővíthetőség és programozhatóság kombinációja. Ebben az útmutatóban a C# által engedélyezett U-SQL nyelv bővíthetőségére és programozhatóságára összpontosítunk.
Követelmények
Töltse le és telepítse az Azure Data Lake Tools for Visual Studiót.
U-SQL – első lépések
Tekintse meg a következő U-SQL-szkriptet:
@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;
Ez a szkript két RowSetet határoz meg: @a
és @results
. A RowSet @results
a-ből @a
van definiálva.
C#-típusok és -kifejezések az U-SQL-szkriptben
Az U-SQL-kifejezés egy olyan C#-kifejezés, amely U-SQL logikai műveletekkel ( , AND
OR
és NOT
) van kombinálva. Az U-SQL-kifejezések a SELECT, EXTRACT, WHERE, HAVING, GROUP BY és DEKLAR paranccsal használhatók. Az alábbi szkript például dateTime értékként elemzi a sztringet.
@results =
SELECT
customer,
amount,
DateTime.Parse(date) AS date
FROM @a;
Az alábbi kódrészlet egy sztringet DateTime értékként elemez egy DECLARE utasításban.
DECLARE @d = DateTime.Parse("2016/01/01");
C#-kifejezések használata adattípus-konverziókhoz
Az alábbi példa bemutatja, hogyan végezhet datetime adatkonvertálást C#-kifejezések használatával. Ebben a konkrét forgatókönyvben a sztringdátum/idő adatok normál dátum/idő értékre lesznek konvertálva 00:00:00 éjféli idő jelöléssel.
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#-kifejezések használata a mai dátumhoz
A mai dátum lekéréséhez a következő C#-kifejezést használhatjuk: DateTime.Now.ToString("M/d/yyyy")
Íme egy példa a kifejezés szkriptben való használatára:
@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-szerelvények használata
A U-SQL bővíthetőségi modellje nagymértékben támaszkodik az egyéni kód .NET-szerelvényekből való hozzáadására.
.NET-szerelvény regisztrálása
CREATE ASSEMBLY
A utasítással helyezzen egy .NET-szerelvényt egy U-SQL Database. Ezt követően az U-SQL-szkriptek a utasítással használhatják ezeket a REFERENCE ASSEMBLY
szerelvényeket.
Az alábbi kód bemutatja, hogyan regisztrálhat szerelvényt:
CREATE ASSEMBLY MyDB.[MyAssembly]
FROM "/myassembly.dll";
Az alábbi kód bemutatja, hogyan hivatkozhat egy szerelvényre:
REFERENCE ASSEMBLY MyDB.[MyAssembly];
Tekintse meg részletesebben a témakört ismertető szerelvényregisztrációs utasításokat .
Szerelvény verziószámozásának használata
A U-SQL jelenleg a .NET-keretrendszer 4.7.2-es verzióját használja. Ezért győződjön meg arról, hogy a saját szerelvények kompatibilisek a futtatókörnyezet adott verziójával.
Ahogy korábban említettük, az U-SQL 64 bites (x64) formátumban futtatja a kódot. Ezért győződjön meg arról, hogy a kód úgy van lefordítva, hogy x64-en fusson. Ellenkező esetben a korábban megjelenő helytelen formátumhiba jelenik meg.
Minden feltöltött szerelvény DLL-je és erőforrásfájlja, például egy másik futtatókörnyezet, natív szerelvény vagy konfigurációs fájl legfeljebb 400 MB lehet. Az üzembe helyezett erőforrások teljes mérete a DEPLOY RESOURCE vagy a szerelvényekre és más fájlokra mutató hivatkozásokon keresztül nem haladhatja meg a 3 GB-ot.
Végül minden U-SQL-adatbázis csak egy adott szerelvény egy verzióját tartalmazhatja. Ha például a NewtonSoft Json.NET könyvtár 7-es és 8-os verziójára is szüksége van, két különböző adatbázisban kell regisztrálnia őket. Ezenkívül minden szkript csak egy adott szerelvény-DLL-verzióra hivatkozhat. Ebben a tekintetben az U-SQL a C# összeállítás-menedzsment és a verziószámozás szemantikáját követi.
Felhasználó által definiált függvények használata: UDF
Az U-SQL felhasználó által definiált függvények vagy UDF-ek olyan programozási rutinok, amelyek paramétereket fogadnak el, műveleteket hajtanak végre (például összetett számítást), és értékként visszaadják a művelet eredményét. Az UDF visszatérési értéke csak egyetlen skaláris lehet. Az U-SQL UDF az U-SQL alapszkriptben hívható meg, mint bármely más C#-skaláris függvény.
Javasoljuk, hogy inicializálja a felhasználó által definiált U-SQL-függvényeket nyilvános és statikusként.
public static string MyFunction(string param1)
{
return "my result";
}
Először nézzük meg az UDF létrehozásának egyszerű példáját.
Ebben a használatieset-forgatókönyvben meg kell határoznunk a pénzügyi időszakot, beleértve az adott felhasználó első bejelentkezésének pénzügyi negyedévét és pénzügyi hónapját. A forgatókönyvünkben az év első pénzügyi hónapja a június.
A pénzügyi időszak kiszámításához a következő C# függvényt vezetjük be:
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();
}
Egyszerűen kiszámítja a pénzügyi hónapot és a negyedévet, és egy sztringértéket ad vissza. Júniusban, az első pénzügyi negyedév első hónapjában az "1.1. negyedévet" használjuk. Júliusban a "Q1:P2" kifejezést használjuk, és így tovább.
Ez egy normál C#-függvény, amelyet a U-SQL-projektben fogunk használni.
Ebben a forgatókönyvben a kód mögötti szakasz a következőképpen néz ki:
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();
}
}
}
Most ezt a függvényt az alap U-SQL-szkriptből fogjuk meghívni. Ehhez meg kell adnunk a függvény teljes nevét, beleértve a névteret is, amely ebben az esetben a NameSpace.Class.Function(paraméter).
USQL_Programmability.CustomFunctions.GetFiscalPeriod(dt)
A tényleges U-SQL-alapszkript a következő:
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();
A szkript végrehajtásának kimeneti fájlja a következő:
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",""
Ez a példa a beágyazott UDF egyszerű használatát mutatja be az U-SQL-ben.
Állapot megőrzése az UDF-meghívások között
Az U-SQL C#-programozhatósági objektumok kifinomultabbak lehetnek, és interaktivitást használnak a globális változók mögötti kóddal. Vizsgáljuk meg a következő üzleti használati esetet.
A nagy szervezetekben a felhasználók válthatnak a belső alkalmazások fajtái között. Ezek közé tartozhat a Microsoft Dynamics CRM, a Power BI és így tovább. Előfordulhat, hogy az ügyfelek telemetriai elemzést szeretnének alkalmazni arról, hogy a felhasználók hogyan váltanak a különböző alkalmazások között, mik a használati trendek stb. A vállalkozás célja az alkalmazáshasználat optimalizálása. Emellett érdemes lehet különböző alkalmazásokat vagy adott bejelentkezési rutinokat kombinálni.
A cél eléréséhez meg kell határoznunk a munkamenet-azonosítókat és az utolsó munkamenet közötti késési időt.
Meg kell találnunk egy korábbi bejelentkezést, majd hozzá kell rendelnünk ezt a bejelentkezést az összes olyan munkamenethez, amely ugyanahhoz az alkalmazáshoz lesz létrehozva. Az első kihívás az, hogy az U-SQL alapszkriptje nem teszi lehetővé, hogy számításokat alkalmazzunk a lag függvénnyel rendelkező, már kiszámított oszlopokra. A második kihívás az, hogy az adott munkamenetet az összes munkamenethez ugyanabban az időszakban kell megtartanunk.
A probléma megoldásához egy globális változót használunk egy kód mögötti szakaszban: static public string globalSession;
.
Ezt a globális változót a szkript végrehajtása során a rendszer a teljes sorkészletre alkalmazza.
Íme az U-SQL-program kód mögötti szakasza:
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;
}
}
}
Ez a példa a függvényben getStampUserSession
használt globális változót static public string globalSession;
mutatja be, és a Munkamenet paraméter minden módosításakor újrainicializálódik.
Az U-SQL alapszkriptje a következő:
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();
A függvényt USQLApplication21.UserSession.getStampUserSession(UserSessionTimestamp)
itt hívjuk meg a második memóriasorkészlet kiszámítása során. Átadja az oszlopot, UserSessionTimestamp
és visszaadja az értéket, amíg meg nem UserSessionTimestamp
változik.
A kimeneti fájl a következő:
"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"
Ez a példa egy bonyolultabb használatieset-forgatókönyvet mutat be, amelyben egy globális változót használunk egy kód mögötti szakaszban, amely a teljes memóriasorkészletre vonatkozik.