Udostępnij za pośrednictwem


Sprzężenia przedziału czasu

Dotyczy: ✅Microsoft FabricAzure Data ExplorerAzure MonitorMicrosoft 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 typu string z identyfikatorami korelacji.
  • EventType: kolumna typu string, która identyfikuje typ zdarzenia rekordu.
  • Timestamp: kolumna typu datetime 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
  • operator sprzężenia