Sprzężenia przedziału czasu
Dotyczy: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
Często przydaje się łączenie między dwoma dużymi zestawami danych w pewnym kluczu o wysokiej kardynalności, takim jak identyfikator operacji lub identyfikator sesji, a następnie ograniczenie rekordów po prawej stronie ($right), które muszą być dopasowane do każdego rekordu po lewej stronie ($left), dodając ograniczenie dotyczące "odległości czasowej" między datetime
kolumnami po lewej i po prawej stronie.
Powyższa operacja różni się od zwykłej operacji sprzężenia, ponieważ w przypadku equi-join
części dopasowania klucza o wysokiej kardynalności między zestawami danych po lewej i prawej stronie system może również zastosować funkcję odległości i użyć jej do znacznego przyspieszenia sprzężenia.
Nuta
Funkcja odległości nie zachowuje się jak równość (czyli gdy zarówno dist(x,y) i dist(y,z) są prawdziwe, że nie następuje, że dist(x,z) jest również prawdziwe. Czasami jest to nazywane "sprzężenie ukośne".
Przykład identyfikowania sekwencji zdarzeń bez przedziału czasu
Aby zidentyfikować sekwencje zdarzeń w stosunkowo małym przedziale czasu, w tym przykładzie użyto tabeli T
z następującym schematem:
-
SessionId
: kolumna typustring
z identyfikatorami korelacji. -
EventType
: kolumna typustring
, która identyfikuje typ zdarzenia rekordu. -
Timestamp
: kolumna typudatetime
wskazuje, kiedy wystąpiło zdarzenie opisane przez rekord.
Identyfikator sesji | EventType | Sygnatury czasowej |
---|---|---|
0 | A | 2017-10-01T00:00:00Z |
0 | B | 2017-10-01T00:01:00Z |
1 | B | 2017-10-01T00:02:00Z |
1 | A | 2017-10-01T00:03:00Z |
3 | A | 2017-10-01T00:04:00Z |
3 | B | 2017-10-01T00:10:00Z |
Poniższe zapytanie tworzy zestaw danych, a następnie identyfikuje wszystkie identyfikatory sesji, w których typ zdarzenia A
był obserwowany przez typ zdarzenia B
w 1min
przedziale czasu.
Uruchom zapytania
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
wyjściowe
Identyfikator sesji | Początek | Koniec |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
Przykład zoptymalizowany przy użyciu przedziału czasu
Aby zoptymalizować to zapytanie, możemy zapisać je ponownie, aby uwzględnić przedział czasu. Przedział czasu THe jest wyrażony jako klucz sprzężenia. Zapisz ponownie zapytanie, aby wartości datetime
zostały "zdyretowane" w zasobnikach, których rozmiar jest połowę rozmiaru okna czasowego. Użyj equi-join
, aby porównać identyfikatory zasobników.
Zapytanie znajduje pary zdarzeń w ramach tej samej sesji (SessionId), gdzie zdarzenie "A" następuje zdarzenie "B" w ciągu 1 minuty. Projektuje identyfikator sesji, godzinę rozpoczęcia zdarzenia "A" i godzinę zakończenia zdarzenia "B".
Uruchom zapytania
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
wyjściowe
Identyfikator sesji | Początek | Koniec |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
5 milionów zapytań dotyczących danych
Następne zapytanie emuluje obszerny zestaw danych 5M rekordów i około 1 mln identyfikatorów sesji i uruchamia zapytanie przy użyciu techniki przedziału czasu.
Uruchom zapytania
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
wyjściowe
Hrabia |
---|
3344 |