Freigeben über


Zeitfensterbeitritt

Gilt für: ✅Microsoft FabricAzure Data ExplorerAzure MonitorMicrosoft 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 Typ string mit Korrelations-IDs.
  • EventType: Eine Spalte vom Typ string, die den Ereignistyp des Datensatzes identifiziert.
  • Timestamp: Eine Spalte vom Typ datetime 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