
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 tek vi dataa som er transformerte til eit maskinlesbart format i Azure Databricks, og lagrar dei i Azure SQL Database for seinare bruk i rapportering.
Viss du gjekk glipp av det, finn du ei lenkje til del 3 her.
All koden som blir brukt i dette innlegget, er tilgjengeleg på GitHub her.
Du kan hoppe over dette steget viss det ikkje er relevant. Elles må vi først opprette ein logisk Azure SQL-server som skal vere vert for databasen, og deretter opprette sjølve databasen.
##Køyr viss Az PowerShell-modulen ikkje alt er installert
Install-Module Az -AllowClobber
##Køyr viss Az PowerShell-modulen alt er installert, men oppdateringskontroll er nødvendig
Update-Module Az
Import-Module Az
Connect-AzAccount
$resourceGroup = '<same resource group som vi har brukt så langt>'
$serverName = $resourceGroup + '-sql'
$databaseName = 'reportingDatabase'
$location = '<same location som dei andre ressursane er distribuerte til, til dømes uksouth>'
## currentUser trengst for at vi kan logge på med gjeldande brukar 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 frå Azure Data Factory
$keyVault = '<Key Vault-en vi har brukt>'
##Du blir beden om å skrive inn eit brukarnamn og passord som blir lagra i denne variabelen som ein 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
##Køyr berre viss du bruker eit public endpoint for SQL-serveren
New-AzSqlServerFirewallRule -AllowAllAzureServices 'AllowMyAccess' -ServerName $serverName -ResourceGroupName $resourceGroup
##Storleiken som blir vist, er 2 GB. Då dette blei skrive, var dette det minste Azure SQL Database-tilbodet i Basic-serien i DTU-prismodellen
New-AzSqlDatabase -DatabaseName $databaseName -ResourceGroupName $resourceGroup -ServerName $serverName -BackupStorageRedundancy 'Local' -Edition 'Basic' -LicenseType 'BasePrice' -MaxSizeBytes 2147483648
--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
--Opprett databasebrukar for login-en som nettopp blei oppretta, i konteksten til reportingDatabase
CREATE USER [<Name of our data factory>] FROM LOGIN [<Name of our data factory>]
--Legg databasebrukaren 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 å køyre stored procedures som vi treng for å merge data fortløpande 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
.For fact-datasettet vårt finst det nokre dimension-tabellar som hjelper oss å analysere dataa på ulike måtar: DimDate og DimHTTPCode. Her er koden eg bruker for å opprette og fylle desse tabellane.
--Køyr 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 måndag som første dag i veka
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
--Køyr 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')
Let’s create the staging and fact tables
--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
Viss vi lagra dataa i eit Kimball data warehouse, ville vi sikre at skjemaet følgjer eit star schema. Vi har delvis gjort dette ved å leggje til date- og HTTP code-dimensjonar med foreign key-relasjonar. For å følgje Kimball-metodikken fullt ut, ville vi òg oppretta dimensjonar for andre datapunkt, som User Action Type, Client OS, Client Type og Client City/State/Country. Dette optimaliserer datalagringa: Det tek til dømes langt mindre plass å lagre heiltal som foreign key i fact-tabellen enn ein string-verdi. SQL Server utfører òg joins på heiltalsverdiar betre enn joins på strings. I endelege fact-tabellar ville vi heller ikkje tillate nullable-verdiar.
I ADF kunne vi ganske enkelt brukt ei Copy data-oppgåve som overfører dei reinsa dataa frå Databricks direkte til fact-tabellen. Det er likevel stor risiko for duplisering, avhengig av kor ofte ADF-pipelinane blir køyrde og kva tidsperiode som er angitt i Log Analytics-function-en. I dette tilfellet opprettar vi ein stored procedure som vel postar som nyleg er kopierte til staging-tabellen i gjeldande pipeline-køyring. Han joiner deretter datasettet med relevante tabellar og kolonnar – her berre DimHTTPCode – for å hente foreign/surrogate key-verdien som skal brukast i fact-tabellen. Vi gir òg kolonnane nye namn slik at dei samsvarer med det endelege tabellskjemaet og koden blir ryddigare.
```sql
--Køyr i konteksten til reportingDatabase
CREATE PROCEDURE [dbo].[sp_MergeWebsiteStatsToLive]
@adfPipelineRunId NVARCHAR(36)
AS
--Vel alle nyleg tilførte postar inn i ein mellombels tabell og join mot rette postar i dimension-tabellane ved behov.
--I dette tilfellet er det berre DimHTTPCode vi hentar ein verdi frå, fordi vi bruker primary/surrogate key-kolonnen frå tabellen i staden
--for å skrive HTTP Code-verdien eksplisitt kvar gong. Vi joiner ikkje mot DimDate fordi dette er ein 1-til-1-join med same verdi på kvar
--side av relasjonen. Vi gir òg kolonnane i den mellombelse tabellen nye namn slik at dei samsvarer med skjemaet til den endelege 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
--No merger vi postar som ikkje allereie finst 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 storleiken på staging-tabellen ved å behalde avgrensa historikk, i dette tilfellet éi veke.
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 nokre nye datasets.
@dataset().container
@dataset().folderPath
@dataset().fileName
@dataset().container
@dataset().folderPath
@activity('Transform Source Data').output.runOutput
loganalytics, som er namnet 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
Då er vi i mål: Vi har no kopiert dataa til Azure SQL-databasen med ADF, klare for rapportering.
Med det er denne serien om å hente ut data frå Log Analytics avslutta.