Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Importante
O Azure Data Lake Analytics foi desativado em 29 de fevereiro de 2024. Saiba mais com este anúncio.
Para análise de dados, sua organização pode usar o Azure Synapse Analytics ou o Microsoft Fabric.
U-SQL é uma linguagem de consulta projetada para cargas de trabalho do tipo big data. Um dos recursos exclusivos do U-SQL é a combinação da linguagem declarativa semelhante ao SQL com a extensibilidade e a programação fornecidas pelo C#. Neste guia, nos concentramos na extensibilidade e programação da linguagem U-SQL habilitada pelo C#.
Requerimentos
Baixe e instale o Azure Data Lake Tools for Visual Studio.
Introdução ao U-SQL
Observe o seguinte script U-SQL:
@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;
Este script define dois RowSets: @a e @results. RowSet @results é definido a partir de @a.
Tipos e expressões C# em script U-SQL
Uma expressão U-SQL é uma expressão C# combinada com operações lógicas U-SQL como AND, ORe NOT. As expressões U-SQL podem ser usadas com SELECT, EXTRACT, WHERE, HAVE, GROUP BY e DECLARE. Por exemplo, o script a seguir analisa uma cadeia de caracteres como um valor DateTime.
@results =
SELECT
customer,
amount,
DateTime.Parse(date) AS date
FROM @a;
O trecho a seguir analisa uma string como valor DateTime em instrução DECLARE.
DECLARE @d = DateTime.Parse("2016/01/01");
Usar expressões C# para conversões de tipo de dados
O exemplo a seguir demonstra como você pode fazer uma conversão de dados datetime usando expressões C#. Nesse cenário específico, os dados datetime da cadeia de caracteres são convertidos em datetime padrão com notação de hora 00:00:00 da meia-noite.
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();
Usar expressões em C# para a data de hoje
Para puxar a data de hoje, podemos usar a seguinte expressão C#: DateTime.Now.ToString("M/d/yyyy")
Aqui está um exemplo de como usar essa expressão em um 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;
Usando assemblies .NET
O modelo de extensibilidade do U-SQL depende muito da capacidade de adicionar código personalizado de assemblies .NET.
Registar um assembli .NET
Utilize a instrução CREATE ASSEMBLY para colocar um assembly .NET em uma base de dados U-SQL. Depois, scripts U-SQL podem usar esses assemblies usando a REFERENCE ASSEMBLY instrução.
O código a seguir mostra como registrar um assembly:
CREATE ASSEMBLY MyDB.[MyAssembly]
FROM "/myassembly.dll";
O código seguinte mostra como fazer referência a um assembly:
REFERENCE ASSEMBLY MyDB.[MyAssembly];
Consulte as instruções de registro de montagem que abordam este tópico com mais detalhes.
Usar controle de versão de assembly
Atualmente, o U-SQL usa o .NET Framework versão 4.7.2. Portanto, certifique-se de que seus próprios assemblies sejam compatíveis com essa versão do tempo de execução.
Como mencionado anteriormente, o U-SQL executa código em um formato de 64 bits (x64). Portanto, certifique-se de que seu código é compilado para ser executado em x64. Caso contrário, você receberá o erro de formato incorreto mostrado anteriormente.
Cada DLL de assembly e ficheiro de recursos enviado, como um tempo de execução diferente, uma assembly nativa ou um ficheiro de configuração, pode ter no máximo 400 MB. O tamanho total dos recursos implantados, seja por meio de DEPLOY RESOURCE ou por meio de referências a assemblies e seus outros arquivos, não pode exceder 3 GB.
Finalmente, cada banco de dados U-SQL só pode conter uma versão de qualquer assembly específico. Por exemplo, se você precisar da versão 7 e da versão 8 da biblioteca NewtonSoft Json.NET, precisará registrá-las em dois bancos de dados diferentes. Além disso, cada script só pode se referir a uma versão de uma determinada DLL de assembly. A esse respeito, o U-SQL segue a semântica de gerenciamento de assembly e versionamento em C#.
Usar funções definidas pelo usuário: UDF
As funções definidas pelo usuário do U-SQL, ou UDF, são rotinas de programação que aceitam parâmetros, executam uma ação (como um cálculo complexo) e retornam o resultado dessa ação como um valor. O valor de retorno de UDF só pode ser um único escalar. O U-SQL UDF pode ser chamado no script base U-SQL como qualquer outra função escalar C#.
Recomendamos que você inicialize funções definidas pelo usuário U-SQL como públicas e estáticas.
public static string MyFunction(string param1)
{
return "my result";
}
Primeiro, vejamos o exemplo simples de criação de um UDF.
Neste cenário de caso de uso, precisamos determinar o período fiscal, incluindo o trimestre fiscal e o mês fiscal do primeiro login para o usuário específico. O primeiro mês fiscal do ano em nosso cenário é junho.
Para calcular o período fiscal, introduzimos a seguinte função C#:
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();
}
Ele simplesmente calcula o mês e o trimestre fiscais e retorna um valor de cadeia de caracteres. Para junho, o primeiro mês do primeiro trimestre fiscal, usamos "Q1:P1". Para julho, usamos "Q1:P2", e assim por diante.
Esta é uma função C# regular que vamos usar em nosso projeto U-SQL.
Veja como a seção code-behind se parece nesse cenário:
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();
}
}
}
Agora vamos chamar essa função a partir do script U-SQL base. Para fazer isso, temos que fornecer um nome totalmente qualificado para a função, incluindo o namespace, que neste caso é NameSpace.Class.Function(parameter).
USQL_Programmability.CustomFunctions.GetFiscalPeriod(dt)
A seguir está o script de base U-SQL real:
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 seguir está o arquivo de saída da execução do script:
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",""
Este exemplo demonstra um uso simples de UDF embutido em U-SQL.
Manter o estado entre invocações UDF
Os objetos de programação U-SQL C# podem ser mais sofisticados, utilizando a interatividade através das variáveis globais no code-behind. Vejamos o seguinte cenário de caso de uso comercial.
Em grandes organizações, os usuários podem alternar entre variedades de aplicativos internos. Eles podem incluir Microsoft Dynamics CRM, Power BI e assim por diante. Os clientes podem querer aplicar uma análise de telemetria de como os usuários alternam entre diferentes aplicativos, quais são as tendências de uso e assim por diante. O objetivo para a empresa é otimizar o uso do aplicativo. Eles também podem querer combinar diferentes aplicativos ou rotinas de logon específicas.
Para atingir esse objetivo, temos que determinar IDs de sessão e tempo de atraso entre a última sessão que ocorreu.
Precisamos encontrar um login anterior e, em seguida, atribuir esse login a todas as sessões que estão sendo geradas para o mesmo aplicativo. O primeiro desafio é que o script base U-SQL não nos permite aplicar cálculos sobre colunas já calculadas com a função LAG. O segundo desafio é que temos de manter a sessão específica para todas as sessões dentro do mesmo período de tempo.
Para resolver esse problema, usamos uma variável global dentro de uma seção code-behind: static public string globalSession;.
Essa variável global é aplicada a todo o conjunto de linhas durante a execução do script.
Aqui está a secção de código subjacente do nosso programa U-SQL:
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;
}
}
}
Este exemplo mostra a variável static public string globalSession; global usada dentro da getStampUserSession função e sendo reinicializada cada vez que o parâmetro Session é alterado.
O script base U-SQL é o seguinte:
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 função USQLApplication21.UserSession.getStampUserSession(UserSessionTimestamp) é chamada aqui durante o segundo cálculo do conjunto de linhas de memória. Ele passa pela UserSessionTimestamp coluna e retorna o valor até que UserSessionTimestamp tenha mudado.
O arquivo de saída é o seguinte:
"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"
Este exemplo demonstra um cenário de caso de uso mais complicado no qual usamos uma variável global dentro de uma seção code-behind que é aplicada a todo o conjunto de linhas de memória.