Zeitfensterbeitritt
Gilt für: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
Es ist häufig nützlich, zwischen zwei großen Datasets mit einem bestimmten Schlüssel mit hoher Kardinalität zu verbinden, z. B. eine Vorgangs-ID oder eine Sitzungs-ID, und die rechtsseitigen ($right) Datensätze weiter einschränken, die mit jedem linken ($left) -Datensatz übereinstimmen müssen, indem eine Einschränkung für die "Zeitabstand" zwischen datetime
Spalten auf der linken und rechten Seite hinzugefügt wird.
Der oben genannte Vorgang unterscheidet sich von dem üblichen Verknüpfungsvorgang, da das System für den equi-join
Teil des Abgleichs des Hauptschlüssels zwischen dem linken und rechten Dataset auch eine Entfernungsfunktion anwenden und es verwenden kann, um die Verknüpfung erheblich zu beschleunigen.
Anmerkung
Eine Abstandsfunktion verhält sich nicht wie Gleichheit (d. h., wenn sowohl dist(x,y) als auch dist(y,z) wahr sind, folgt es nicht, dass dist(x,z) ebenfalls wahr ist.) Dies wird manchmal als "diagonale Verknüpfung" bezeichnet.
Beispiel zum Identifizieren von Ereignissequenzen ohne Zeitfenster
Um Ereignissequenzen innerhalb eines relativ kleinen Zeitfensters zu identifizieren, verwendet dieses Beispiel eine Tabelle T
mit dem folgenden Schema:
-
SessionId
: Eine Spalte vom Typstring
mit Korrelations-IDs. -
EventType
: Eine Spalte vom Typstring
, die den Ereignistyp des Datensatzes identifiziert. -
Timestamp
: Eine Spalte vom Typdatetime
angibt, wann das vom Datensatz beschriebene Ereignis aufgetreten ist.
SessionId | EventType | Zeitstempel |
---|---|---|
0 | Ein | 2017-10-01T00:00:00Z |
0 | B | 2017-10-01T00:01:00Z |
1 | B | 2017-10-01T00:02:00Z |
1 | Ein | 2017-10-01T00:03:00Z |
3 | Ein | 2017-10-01T00:04:00Z |
3 | B | 2017-10-01T00:10:00Z |
Die folgende Abfrage erstellt das Dataset und identifiziert dann alle Sitzungs-IDs, in denen A
Ereignistyp gefolgt wurde, B
innerhalb eines 1min
Zeitfensters.
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
Ausgabe-
SessionId | Anfangen | Ende |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
Beispiel für zeitoptimiertes Zeitfenster
Um diese Abfrage zu optimieren, können wir sie neu schreiben, um das Zeitfenster zu berücksichtigen. THe-Zeitfenster wird als Verknüpfungsschlüssel ausgedrückt. Schreiben Sie die Abfrage neu, sodass die datetime
Werte in Buckets "diskretisiert" werden, deren Größe die Hälfte der Größe des Zeitfensters beträgt. Verwenden Sie equi-join
, um die Bucket-IDs zu vergleichen.
Die Abfrage findet Paare von Ereignissen innerhalb derselben Sitzung (SessionId), wobei ein "A"-Ereignis innerhalb von 1 Minute von einem "B"-Ereignis gefolgt wird. Es projiziert die Sitzungs-ID, die Startzeit des "A"-Ereignisses und die Endzeit des "B"-Ereignisses.
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
Ausgabe-
SessionId | Anfangen | Ende |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
5 Millionen Datenabfrage
Die nächste Abfrage emuliert ein umfangreiches Dataset mit 5M-Datensätzen und ungefähr 1M Session IDs und führt die Abfrage mit der Zeitfenstertechnik aus.
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
Ausgabe-
Zählen |
---|
3344 |