
Del 3: Rapportering på Log Analytics-data | Behandle data med Azure Databricks
Del 3 av serien om rapportering på Log Analytics-data.
I dette neste innlegget i serien tar vi dataene som er transformert til et maskinlesbart format i Azure Databricks, og lagrer dem i Azure SQL Database for senere bruk i rapportering.
Hvis du gikk glipp av det, finner du en lenke til del 3 her.
All koden som brukes i dette innlegget, er tilgjengelig på GitHub her.
Du kan hoppe over dette steget hvis det ikke er relevant. Ellers må vi først opprette en logisk Azure SQL-server som skal være vert for databasen, og deretter opprette selve databasen.
##Kjør hvis Az PowerShell-modulen ikke allerede er installert
Install-Module Az -AllowClobber
##Kjør hvis Az PowerShell-modulen allerede er installert, men oppdateringskontroll er nødvendig
Update-Module Az
Import-Module Az
Connect-AzAccount
$resourceGroup = '<samme resource group som vi har brukt så langt>'
$serverName = $resourceGroup + '-sql'
$databaseName = 'reportingDatabase'
$location = '<samme location som de andre ressursene er distribuert til, f.eks. uksouth>'
## currentUser trengs for at vi kan logge på med gjeldende bruker ved Azure Active Directory-autentisering
$currentUser = (Get-AzContext).Account
$publicIpAddress = (Invoke-WebRequest -uri 'https://api.ipify.org/').Content
##Vi må lagre connection string i Key Vault for å få tilgang til SQL-databasen fra Azure Data Factory
$keyVault = '<Key Vault-en vi har brukt>'
##Du blir bedt om å skrive inn et brukernavn og passord som lagres i denne variabelen som en secure string
$sqlAdminCredential = Get-Credential
New-AzSqlServer -ServerName $serverName -SqlAdministratorCredentials $sqlAdminCredential -Location $location -ServerVersion '12.0' -PublicNetworkAccess 'enabled' -MinimalTlsVersion '1.2' -ExternalAdminName $currentUser -ResourceGroupName $resourceGroup
New-AzSqlServerFirewallRule -FirewallRuleName 'AllowMyAccess' -StartIpAddress $publicIpAddress -EndIpAddress $publicIpAddress -ServerName $serverName -ResourceGroupName $resourceGroup
##Kjør bare hvis du bruker et public endpoint for SQL-serveren
New-AzSqlServerFirewallRule -AllowAllAzureServices 'AllowMyAccess' -ServerName $serverName -ResourceGroupName $resourceGroup
sqladmin-legitimasjonen vil ikke fungere i de senere stegene, fordi du må autentisere mot AAD når service principal-tilgangen for ADF skal konfigureres.##Størrelsen som vises, er 2 GB. Da dette ble skrevet, var dette det minste Azure SQL Database-tilbudet i Basic-serien i DTU-prismodellen
New-AzSqlDatabase -DatabaseName $databaseName -ResourceGroupName $resourceGroup -ServerName $serverName -BackupStorageRedundancy 'Local' -Edition 'Basic' -LicenseType 'BasePrice' -MaxSizeBytes 2147483648
master-databasen, og kjør følgende:--Opprett SQL Server-login for service principal-en til Azure Data Factory-instansen i konteksten til master-databasen
CREATE LOGIN [<Name of our data factory>] FROM EXTERNAL PROVIDER
reportingDatabase-databasen.--Opprett databasebruker for login-en som nettopp ble opprettet, i konteksten til reportingDatabase
CREATE USER [<Name of our data factory>] FROM LOGIN [<Name of our data factory>]
--Legg databasebrukeren til i database-rollene reader og writer
ALTER ROLE [db_datareader] ADD MEMBER [<Name of our data factory>]
ALTER ROLE [db_datawriter] ADD MEMBER [<Name of our data factory>]
--Opprett database-rolle for å kjøre stored procedures som vi trenger for å merge data fortløpende og unngå duplisering
CREATE ROLE [db_spexector]
GRANT EXECUTE TO [db_spexector]
ALTER ROLE [db_spexector] ADD MEMBER [<Name of our data factory>]
##Lagre connection string til SQL-databasen i Azure Key Vault
$connectionString = ConvertTo-SecureString -String ('Data Source=' + $serverName + '.database.windows.net;Initial Catalog=' + $databaseName + ';') -AsPlainText
Set-AzKeyVaultSecret -VaultName $keyVault -Name 'sql-connection-string' -SecretValue $connectionString
.DimDate og DimHTTPCode. Her er koden jeg bruker for å opprette og fylle disse tabellene.--Kjør i konteksten til reportingDatabase
--Opprett DimDate-tabellen
CREATE TABLE [dbo].[DimDate]
(
[Date_Value] DATE NOT NULL,
[Day_Number_Month] TINYINT NOT NULL,
[Day_Number_Week] TINYINT NOT NULL,
[Week_Number_CY] TINYINT NOT NULL,
[Month_Number_CY] TINYINT NOT NULL,
[Quarter_Number_CY] TINYINT NOT NULL,
[Day_Name_Long] NVARCHAR(9) NOT NULL,
[Day_Name_Short] NCHAR(3) NOT NULL,
[Month_Name_Long] NVARCHAR(9) NOT NULL,
[Month_Name_Short] NCHAR(3) NOT NULL,
[Quarter_Name_CY] NCHAR(2) NOT NULL,
[Year_Quarter_Name_CY] NVARCHAR(7) NOT NULL,
[IsWeekday] BIT NOT NULL,
[IsWeekend] BIT NOT NULL,
CONSTRAINT [PK_DimDate] PRIMARY KEY CLUSTERED
(
[Date_Value] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
--Fyll DimDate
DECLARE @StartDate AS DATE
SET @StartDate = '2020-01-01'
DECLARE @EndDate AS DATE
SET @EndDate = '2025-12-31'
DECLARE @LoopDate AS DATE
SET @Loopdate = @StartDate
--Angir mandag som første dag i uken
SET DATEFIRST 1
WHILE @Loopdate < @EndDate
BEGIN
INSERT INTO [dbo].[DimDate]
VALUES (
-- [Date_Value]
@LoopDate,
--[Day_Number_Month]
DATEPART(DAY, @LoopDate),
-- [Day_Number_Week]
DATEPART(WEEKDAY, @LoopDate),
-- [Week_Number_CY]
DATENAME(WEEK, @LoopDate),
-- [Month_Number_CY]
MONTH(@LoopDate),
--[Quarter_Number_CY]
DATEPART(QUARTER, @LoopDate),
-- [Day_Name_Long]
DATENAME(WEEKDAY, @LoopDate),
--[Day_Name_Short]
FORMAT(@LoopDate, 'ddd'),
-- [Month_Name_Long]
DATENAME(MONTH, @LoopDate),
-- [Month_Name_Short]
FORMAT(@LoopDate, 'MMM'),
-- [Quarter_Name_CY]
CONCAT ('Q',DATEPART(QUARTER, @LoopDate)),
-- [Year_Quarter_Name_CY]
CONCAT (YEAR(@LoopDate),'-Q',DATEPART(QUARTER, @LoopDate)),
--[IsWeekday]
CASE WHEN DATEPART(WEEKDAY, @LoopDate) IN (1,2,3,4,5) THEN 1 ELSE 0 END,
-- [IsWeekend]
CASE WHEN DATEPART(WEEKDAY, @LoopDate) IN (6,7) THEN 1 ELSE 0 END
)
SET @Loopdate = DATEADD(DAY, 1, @LoopDate)
END
--Kjør i konteksten til reportingDatabase
--Opprett DimHttpCode-tabellen
CREATE TABLE [dbo].[DimHTTPCode] (
[Http_Code_Key] INT IDENTITY(1,1) NOT NULL,
[Http_Error_Code] INT NOT NULL,
[Http_Error_Code_Description] NVARCHAR(150) NOT NULL,
CONSTRAINT [PK_DimHTTPCode] PRIMARY KEY CLUSTERED
(
[Http_Code_Key] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
--Fyll DimHttpCode-tabellen
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('100','Continue')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('101','Switching Protocols')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('102','Processing')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('103','Early Hints')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('200','OK')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('201','Created')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('202','Accepted')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('203','Non-Authoritative Information')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('204','No Content')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('205','Reset Content')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('206','Partial Content')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('207','Multi-Status')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('208','Already Reported')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('226','IM Used')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('300','Multiple Choices')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('301','Moved Permanently')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('302','Found')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('303','See Other')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('304','Not Modified')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('305','Use Proxy')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('306','(Unused)')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('307','Temporary Redirect')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('308','Permanent Redirect')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('400','Bad Request')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('401','Unauthorized')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('402','Payment Required')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('403','Forbidden')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('404','Not Found')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('405','Method Not Allowed')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('406','Not Acceptable')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('407','Proxy Authentication Required')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('408','Request Timeout')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('409','Conflict')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('410','Gone')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('411','Length Required')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('412','Precondition Failed')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('413','Content Too Large')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('414','URI Too Long')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('415','Unsupported Media Type')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('416','Range Not Satisfiable')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('417','Expectation Failed')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('418','(Unused)')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('421','Misdirected Request')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('422','Unprocessable Content')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('423','Locked')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('424','Failed Dependency')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('425','Too Early')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('426','Upgrade Required')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('427','Unassigned')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('428','Precondition Required')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('429','Too Many Requests')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('430','Unassigned')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('431','Request Header Fields Too Large')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('451','Unavailable For Legal Reasons')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('500','Internal Server Error')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('501','Not Implemented')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('502','Bad Gateway')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('503','Service Unavailable')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('504','Gateway Timeout')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('505','HTTP Version Not Supported')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('506','Variant Also Negotiates')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('507','Insufficient Storage')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('508','Loop Detected')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('509','Unassigned')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('510','Not Extended (OBSOLETED)')
INSERT INTO [dbo].[DimHTTPCode] ([Http_Error_Code], [Http_Error_Code_Description]) VALUES ('511','Network Authentication Required')
--Run in the context of reportingDatabase
CREATE TABLE [dbo].[staging_factHubnetCloudWebsiteStats](
[timeGenerated] DATETIME2 NULL,
[userAction] NVARCHAR(500) NULL,
[appUrl] NVARCHAR(500) NULL,
[successFlag] BIT NULL,
[httpResultCode] INT NULL,
[durationOfRequestMs] FLOAT NULL,
[clientType] NVARCHAR(50) NULL,
[clientOS] NVARCHAR(50) NULL,
[clientCity] NVARCHAR(50) NULL,
[clientStateOrProvince] NVARCHAR(50) NULL,
[clientCountryOrRegion] NVARCHAR(50) NULL,
[clientBrowser] NVARCHAR(50) NULL,
[appRoleName] NVARCHAR(50) NULL,
[requestDate] DATE NULL,
[requestHour] TINYINT NULL,
[adfPipelineRunId] NVARCHAR(50) NOT NULL,
[adfCopyTimestamp] DATETIME2 NOT NULL
)
ALTER TABLE [dbo].[staging_factHubnetCloudWebsiteStats] ADD DEFAULT GETUTCDATE() FOR [adfCopyTimestamp]
--Run in the context of reportingDatabase
CREATE TABLE [dbo].[FactHubnetCloudWebsiteStats](
[Request_Timestamp_UTC] DATETIME2 NULL,
[Request_Date_UTC] DATE NULL,
[Request_Hour_UTC] TINYINT NULL,
[Request_User_Action] NVARCHAR(500) NULL,
[Request_App_URL] NVARCHAR(500) NULL,
[Request_Success_Flag] BIT NULL,
[Request_HTTP_Code] INT NULL,
[Request_Duration_Milliseconds] FLOAT NULL,
[Request_Client_Type] NVARCHAR(50) NULL,
[Request_Client_OS] NVARCHAR(50) NULL,
[Request_Client_Browser] NVARCHAR(50) NULL,
[Request_Client_City] NVARCHAR(50) NULL,
[Request_Client_State_Or_Province] NVARCHAR(50) NULL,
[Request_Client_Country_Or_Region] NVARCHAR(50) NULL,
[Request_App_Role_Name] NVARCHAR(50)
)
GO
ALTER TABLE [dbo].[FactHubnetCloudWebsiteStats] ADD CONSTRAINT [FK_FactHubnetCloudWebsiteStats_DimDate] FOREIGN KEY([Request_Date_UTC])
REFERENCES [dbo].[DimDate] ([Date_Value])
GO
ALTER TABLE [dbo].[FactHubnetCloudWebsiteStats] ADD CONSTRAINT [FK_FactHubnetCloudWebsiteStats_DimHTTPCode] FOREIGN KEY([Request_HTTP_Code])
REFERENCES [dbo].[DimHTTPCode] ([Http_Code_Key])
GO
Hvis vi lagret dataene i et Kimball data warehouse, ville vi sikre at skjemaet følger et star schema. Vi har delvis gjort dette ved å legge til date- og HTTP code-dimensjoner med foreign key-relasjoner. For å følge Kimball-metodikken fullt ut, ville vi også opprettet dimensjoner for andre datapunkter, som User Action Type, Client OS, Client Type og Client City/State/Country. Dette optimaliserer datalagringen: Det tar for eksempel langt mindre plass å lagre heltall som foreign key i fact-tabellen enn en string-verdi. SQL Server utfører også joins på heltallsverdier bedre enn joins på strings. I endelige fact-tabeller ville vi heller ikke tillatt nullable-verdier.
I ADF kunne vi ganske enkelt brukt en Copy data-oppgave som overfører de rensede dataene fra Databricks direkte til fact-tabellen. Det er imidlertid stor risiko for duplisering, avhengig av hvor ofte ADF-pipelinene kjøres og hvilken tidsperiode som er angitt i Log Analytics-function-en. I dette tilfellet oppretter vi en stored procedure som velger poster som nylig er kopiert til staging-tabellen i gjeldende pipeline-kjøring. Den joiner deretter datasettet med relevante tabeller og kolonner – her bare DimHTTPCode – for å hente foreign/surrogate key-verdien som skal brukes i fact-tabellen. Vi gir også kolonnene nye navn slik at de samsvarer med det endelige tabellskjemaet og koden blir ryddigere.
```sql
--Kjør i konteksten til reportingDatabase
CREATE PROCEDURE [dbo].[sp_MergeWebsiteStatsToLive]
@adfPipelineRunId NVARCHAR(36)
AS
--Velger alle nylig tilføyde poster inn i en midlertidig tabell og joiner mot riktige poster i dimension-tabellene ved behov.
--I dette tilfellet er det bare DimHTTPCode vi henter en verdi fra, fordi vi bruker primary/surrogate key-kolonnen fra tabellen i stedet
--for å skrive HTTP Code-verdien eksplisitt hver gang. Vi joiner ikke mot DimDate fordi dette er en 1-til-1-join med samme verdi på hver
--side av relasjonen. Vi gir også kolonnene i den midlertidige tabellen nye navn slik at de samsvarer med skjemaet til den endelige fact-tabellen.
SELECT
STG.[timeGenerated] AS [Request_Timestamp_UTC],
STG.[requestDate] AS [Request_Date_UTC],
STG.[requestHour] AS [Request_Hour_UTC],
STG.[userAction] AS [Request_User_Action],
STG.[appUrl] AS [Request_App_URL],
STG.[successFlag] AS [Request_Success_Flag],
DHC.[Http_Code_Key] AS [Request_HTTP_Code],
STG.[durationOfRequestMs] AS [Request_Duration_Milliseconds],
STG.[clientType] AS [Request_Client_Type],
STG.[clientOS] AS [Request_Client_OS],
STG.[clientBrowser] AS [Request_Client_Browser],
STG.[clientCity] AS [Request_Client_City],
STG.[clientStateOrProvince] AS [Request_Client_State_Or_Province],
STG.[clientCountryOrRegion] AS [Request_Client_Country_Or_Region],
STG.[appRoleName] AS [Request_App_Role_Name]
INTO #WebsiteStatsNewRecords
FROM [dbo].[staging_factHubnetCloudWebsiteStats] STG
LEFT JOIN [dbo].[DimHTTPCode] DHC ON STG.[httpResultCode] = DHC.[Http_Error_Code]
WHERE STG.[adfPipelineRunId] = @adfPipelineRunId
--Nå merger vi poster som ikke allerede finnes i fact-tabellen, slik at vi unngår duplisering.
MERGE INTO [dbo].[FactHubnetCloudWebsiteStats] DST
USING #WebsiteStatsNewRecords SRC
ON DST.[Request_Timestamp_UTC] = SRC.[Request_Timestamp_UTC]
AND DST.[Request_Date_UTC] = SRC.[Request_Date_UTC]
AND DST.[Request_Hour_UTC] = SRC.[Request_Hour_UTC]
AND DST.[Request_User_Action] = SRC.[Request_User_Action]
AND DST.[Request_App_URL] = SRC.[Request_App_URL]
AND DST.[Request_Success_Flag] = SRC.[Request_Success_Flag]
AND DST.[Request_HTTP_Code] = SRC.[Request_HTTP_Code]
AND DST.[Request_Duration_Milliseconds] = SRC.[Request_Duration_Milliseconds]
AND DST.[Request_Client_Type] = SRC.[Request_Client_Type]
AND DST.[Request_Client_OS] = SRC.[Request_Client_OS]
AND DST.[Request_Client_Browser] = SRC.[Request_Client_Browser]
AND DST.[Request_Client_City] = SRC.[Request_Client_City]
AND DST.[Request_Client_State_Or_Province] = SRC.[Request_Client_State_Or_Province]
AND DST.[Request_Client_Country_Or_Region] = SRC.[Request_Client_Country_Or_Region]
AND DST.[Request_App_Role_Name] = SRC.[Request_App_Role_Name]
WHEN NOT MATCHED BY TARGET THEN INSERT
(
[Request_Timestamp_UTC],
[Request_Date_UTC],
[Request_Hour_UTC],
[Request_User_Action],
[Request_App_URL],
[Request_Success_Flag],
[Request_HTTP_Code],
[Request_Duration_Milliseconds],
[Request_Client_Type],
[Request_Client_OS],
[Request_Client_Browser],
[Request_Client_City],
[Request_Client_State_Or_Province],
[Request_Client_Country_Or_Region],
[Request_App_Role_Name]
)
VALUES
(
SRC.[Request_Timestamp_UTC],
SRC.[Request_Date_UTC],
SRC.[Request_Hour_UTC],
SRC.[Request_User_Action],
SRC.[Request_App_URL],
SRC.[Request_Success_Flag],
SRC.[Request_HTTP_Code],
SRC.[Request_Duration_Milliseconds],
SRC.[Request_Client_Type],
SRC.[Request_Client_OS],
SRC.[Request_Client_Browser],
SRC.[Request_Client_City],
SRC.[Request_Client_State_Or_Province],
SRC.[Request_Client_Country_Or_Region],
SRC.[Request_App_Role_Name]
);
--Logikk for å kontrollere størrelsen på staging-tabellen ved å beholde begrenset historikk, i dette tilfellet én uke.
DELETE FROM [dbo].[staging_factHubnetCloudWebsiteStats]
WHERE [adfCopyTimestamp] < DATEADD(WEEK,-1,GETUTCDATE())
```
Vi er nesten klare til å implementere logikken i ADF-pipelinen. Dette er siste etappe i denne delen av prosessen. Først må vi opprette noen nye datasets.
@dataset().container
@dataset().folderPath
@dataset().fileName
@dataset().container
@dataset().folderPath
@activity('Transform Source Data').output.runOutput
loganalytics, som er navnet på containeren i data lake-en.@variables('outputFolderPath')
@activity('Get files in output folder').Output.childItems
@endswith(item().name,'snappy.parquet')
@activity('Filter for parquet files').output.Value
loganalytics for parameteren container.@variables('outputFolderPath')
@item().name
/.@pipeline().RunId
Da er vi i mål: Vi har nå kopiert dataene til Azure SQL-databasen med ADF, klare for rapportering.
Med det er denne serien om å hente ut data fra Log Analytics avsluttet.