Delen via


Tijdvensterdeelname

Van toepassing op: ✅Microsoft FabricAzure Data ExplorerAzure MonitorMicrosoft Sentinel-

Het is vaak handig om deel te nemen tussen twee grote gegevenssets op een sleutel met hoge kardinaliteit, zoals een bewerkings-id of een sessie-id, en de records aan de rechterkant ($right) die moeten overeenkomen met elke record aan de linkerkant ($left) door een beperking toe te voegen aan de 'tijdafstand' tussen datetime kolommen aan de linkerkant en aan de rechterkant.

De bovenstaande bewerking verschilt van de gebruikelijke join-bewerking, omdat voor het equi-join deel van het koppelen van de sleutel met hoge kardinaliteit tussen de linker- en rechtergegevenssets ook een afstandsfunctie kan worden toegepast en het systeem kan gebruiken om de join aanzienlijk te versnellen.

Notitie

Een afstandsfunctie gedraagt zich niet als gelijkheid (dus wanneer zowel dist(x,y) als dist(y,z) waar zijn, volgt deze niet dat dist(x,z) ook waar is.) Dit wordt soms een 'diagonale join' genoemd.

Voorbeeld voor het identificeren van gebeurtenisreeksen zonder tijdvenster

Voor het identificeren van gebeurtenisreeksen binnen een relatief klein tijdvenster gebruikt dit voorbeeld een tabel T met het volgende schema:

  • SessionId: een kolom van het type string met correlatie-id's.
  • EventType: een kolom van het type string waarmee het gebeurtenistype van de record wordt geïdentificeerd.
  • Timestamp: Een kolom van het type datetime geeft aan wanneer de gebeurtenis die door de record is beschreven.
SessionId EventType Tijdstempel
0 Een 2017-10-01T00:00:00Z
0 B 2017-10-01T00:01:00Z
1 B 2017-10-01T00:02:00Z
1 Een 2017-10-01T00:03:00Z
3 Een 2017-10-01T00:04:00Z
3 B 2017-10-01T00:10:00Z

De volgende query maakt de gegevensset en identificeert vervolgens alle sessie-id's waarin het gebeurtenistype A werd gevolgd door een gebeurtenistype B binnen een 1min tijdvenster.

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
| 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 

uitvoer

SessionId Beginnen Einde
0 2017-10-01 00:00:00.0000000 2017-10-01 00:01:00.0000000

Voorbeeld geoptimaliseerd met tijdvenster

Om deze query te optimaliseren, kunnen we deze opnieuw schrijven om rekening te houden met het tijdvenster. Het tijdvenster wordt uitgedrukt als een join-sleutel. Herschrijf de query zodat de datetime waarden worden 'discretized' in buckets waarvan de grootte de helft van het tijdvenster is. Gebruik equi-join om de bucket-id's te vergelijken.

De query zoekt paren gebeurtenissen binnen dezelfde sessie (SessionId) waarbij een A-gebeurtenis binnen 1 minuut wordt gevolgd door een B-gebeurtenis. Het projecteert de sessie-id, de begintijd van de gebeurtenis A en de eindtijd van de gebeurtenis B.

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 

uitvoer

SessionId Beginnen Einde
0 2017-10-01 00:00:00.0000000 2017-10-01 00:01:00.0000000

5 miljoen gegevensquery

Met de volgende query wordt een uitgebreide gegevensset van 5M-records en ongeveer 1M Sessie-id's geëmuleerd en wordt de query uitgevoerd met de tijdvenstertechniek.

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 

uitvoer

Tellen
3344