Operátor join s časovým intervalem
Často je užitečné spojit mezi dvěma velkými datovými sadami pomocí některého klíče s vysokou kardinalitou, jako je ID operace nebo ID relace, a dále omezit záznamy na pravé straně ($right), které se musí shodovat s každým záznamem na levé straně ($left), přidáním omezení "časové vzdálenosti" mezi datetime
sloupce vlevo a vpravo.
Výše uvedená operace se liší od obvyklé operace spojení Kusto, protože pro equi-join
část párování klíče s vysokou kardinalitou mezi levou a pravou datovou sadou může systém také použít funkci vzdálenosti a použít ji k podstatnému zrychlení spojení.
Poznámka
Funkce vzdálenosti se nechová jako rovnost (to znamená, že pokud jsou obě hodnoty dist(x,y) i dist(y,z) pravdivé, nevypadá to, že dist(x,z) je také pravda.) Interně se tomu někdy říká "diagonální spojení".
Pokud například chcete identifikovat sekvence událostí v relativně malém časovém intervalu, předpokládejme, že máte tabulku T
s následujícím schématem:
SessionId
: Sloupec typustring
s ID korelace.EventType
: Sloupec typustring
, který identifikuje typ události záznamu.Timestamp
: Sloupec typudatetime
označuje, kdy došlo k události popsané záznamem.
let T = datatable(SessionId:string, EventType:string, Timestamp:datetime)
[
'0', 'A', datetime(2017-10-01 00:00:00),
'0', 'B', datetime(2017-10-01 00:01:00),
'1', 'B', datetime(2017-10-01 00:02:00),
'1', 'A', datetime(2017-10-01 00:03:00),
'3', 'A', datetime(2017-10-01 00:04:00),
'3', 'B', datetime(2017-10-01 00:10:00),
];
T
Výstup
SessionId | Typ události | Timestamp |
---|---|---|
0 | A | 2017-10-01 00:00:00.0000000 |
0 | B | 2017-10-01 00:01:00.0000000 |
1 | B | 2017-10-01 00:02:00.0000000 |
1 | A | 2017-10-01 00:03:00.0000000 |
3 | A | 2017-10-01 00:04:00.0000000 |
3 | B | 2017-10-01 00:10:00.0000000 |
Příkaz k problému
Náš dotaz by měl zodpovědět následující otázku:
Vyhledejte všechna ID relací, ve kterých byl typ A
události následovaný typem B
události v časovém 1min
okně.
Poznámka
Ve výše uvedených ukázkových datech je 0
jediným takovým ID relace .
Sémanticky následující dotaz odpovídá na tuto otázku, i když neefektivně.
T
| where EventType == 'A'
| project SessionId, Start=Timestamp
| join kind=inner
(
T
| where EventType == 'B'
| project SessionId, End=Timestamp
) on SessionId
| where (End - Start) between (0min .. 1min)
| project SessionId, Start, End
Výstup
SessionId | Spustit | End |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
Abychom tento dotaz optimalizovali, můžeme ho přepsat, jak je popsáno níže, aby se časové období vyjádřilo jako klíč spojení.
Přepište dotaz tak, aby se zohlednil časový interval.
Přepište dotaz tak, aby datetime
se hodnoty "diskretizovaly" do kbelíků, jejichž velikost je poloviční než velikost časového intervalu. K porovnání těchto ID kbelíků equi-join
použijte Kusto.
let lookupWindow = 1min;
let lookupBin = lookupWindow / 2.0; // lookup bin = equal to 1/2 of the lookup window
T
| where EventType == 'A'
| project SessionId, Start=Timestamp,
// TimeKey on the left side of the join is mapped to a discrete time axis for the join purpose
TimeKey = bin(Timestamp, lookupBin)
| join kind=inner
(
T
| where EventType == 'B'
| project SessionId, End=Timestamp,
// TimeKey on the right side of the join - emulates event 'B' appearing several times
// as if it was 'replicated'
TimeKey = range(bin(Timestamp-lookupWindow, lookupBin),
bin(Timestamp, lookupBin),
lookupBin)
// 'mv-expand' translates the TimeKey array range into a column
| mv-expand TimeKey to typeof(datetime)
) on SessionId, TimeKey
| where (End - Start) between (0min .. lookupWindow)
| project SessionId, Start, End
Referenční informace k spustitelným dotazům (s vloženou tabulkou)
let T = datatable(SessionId:string, EventType:string, Timestamp:datetime)
[
'0', 'A', datetime(2017-10-01 00:00:00),
'0', 'B', datetime(2017-10-01 00:01:00),
'1', 'B', datetime(2017-10-01 00:02:00),
'1', 'A', datetime(2017-10-01 00:03:00),
'3', 'A', datetime(2017-10-01 00:04:00),
'3', 'B', datetime(2017-10-01 00:10:00),
];
let lookupWindow = 1min;
let lookupBin = lookupWindow / 2.0;
T
| where EventType == 'A'
| project SessionId, Start=Timestamp, TimeKey = bin(Timestamp, lookupBin)
| join kind=inner
(
T
| where EventType == 'B'
| project SessionId, End=Timestamp,
TimeKey = range(bin(Timestamp-lookupWindow, lookupBin),
bin(Timestamp, lookupBin),
lookupBin)
| mv-expand TimeKey to typeof(datetime)
) on SessionId, TimeKey
| where (End - Start) between (0min .. lookupWindow)
| project SessionId, Start, End
Výstup
SessionId | Spustit | End |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
Dotaz na 5M data
Další dotaz emuluje datovou sadu s 5M záznamy a ID ~1M a spustí dotaz pomocí výše popsané techniky.
let T = range x from 1 to 5000000 step 1
| extend SessionId = rand(1000000), EventType = rand(3), Time=datetime(2017-01-01)+(x * 10ms)
| extend EventType = case(EventType < 1, "A",
EventType < 2, "B",
"C");
let lookupWindow = 1min;
let lookupBin = lookupWindow / 2.0;
T
| where EventType == 'A'
| project SessionId, Start=Time, TimeKey = bin(Time, lookupBin)
| join kind=inner
(
T
| where EventType == 'B'
| project SessionId, End=Time,
TimeKey = range(bin(Time-lookupWindow, lookupBin),
bin(Time, lookupBin),
lookupBin)
| mv-expand TimeKey to typeof(datetime)
) on SessionId, TimeKey
| where (End - Start) between (0min .. lookupWindow)
| project SessionId, Start, End
| count
Výstup
Počet |
---|
3344 |
Váš názor
https://aka.ms/ContentUserFeedback.
Připravujeme: V průběhu roku 2024 budeme postupně vyřazovat problémy z GitHub coby mechanismus zpětné vazby pro obsah a nahrazovat ho novým systémem zpětné vazby. Další informace naleznete v tématu:Odeslat a zobrazit názory pro