Associação de janela de tempo
Muitas vezes, é útil associar entre dois grandes conjuntos de dados numa chave de cardinalidade elevada, como um ID de operação ou um ID de sessão, e limitar ainda mais os registos do lado direito ($right) que têm de corresponder a cada registo do lado esquerdo ($left) ao adicionar uma restrição à "distância temporal" entre datetime
colunas à esquerda e à direita.
A operação acima difere da operação de associação kusto habitual, uma vez que, por equi-join
parte da correspondência da chave de cardinalidade elevada entre os conjuntos de dados esquerdo e direito, o sistema também pode aplicar uma função de distância e utilizá-la para acelerar consideravelmente a associação.
Nota
Uma função de distância não se comporta como igualdade (ou seja, quando dist(x,y) e dist(y,z) são verdadeiros, não segue que dist(x,z) também é verdadeiro.) Internamente, por vezes referimo-nos a isto como "associação diagonal".
Por exemplo, se quiser identificar sequências de eventos numa janela de tempo relativamente pequena, suponha que tem uma tabela T
com o seguinte esquema:
SessionId
: uma coluna do tipostring
com IDs de correlação.EventType
: uma coluna do tipostring
que identifica o tipo de evento do registo.Timestamp
: uma coluna do tipodatetime
indica quando ocorreu o evento descrito pelo registo.
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
Saída
SessionId | EventType | CarimboDeDataEHora |
---|---|---|
0 | A | 2017-10-01 00:00:00.0000000 |
0 | B | 2017-10-01 00:01:00.0000000 |
1 | B | 2017-10-01 00:02:00.0000000 |
1 | A | 2017-10-01 00:03:00.0000000 |
3 | A | 2017-10-01 00:04:00.0000000 |
3 | B | 2017-10-01 00:10:00.0000000 |
Declaração de problema
A nossa consulta deve responder à seguinte pergunta:
Localize todos os IDs de sessão em que o tipo A
de evento foi seguido por um tipo B
de evento dentro de um 1min
período de tempo.
Nota
Nos dados de exemplo acima, o único ID dessa sessão é 0
.
Semanticamente, a seguinte consulta responde a esta pergunta, embora ineficientemente.
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
Saída
SessionId | Iniciar | Fim |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
Para otimizar esta consulta, podemos reescrevê-la conforme descrito abaixo para que a janela de tempo seja expressa como uma chave de associação.
Reescrever a consulta para ter em conta a janela de tempo
Reescreva a consulta para que os datetime
valores sejam "discretos" em registos cujo tamanho seja metade do tamanho da janela de tempo. Utilize o Kusto's equi-join
para comparar esses IDs de registo.
let lookupWindow = 1min;
let lookupBin = lookupWindow / 2.0; // lookup bin = equal to 1/2 of the lookup window
T
| where EventType == 'A'
| project SessionId, Start=Timestamp,
// TimeKey on the left side of the join is mapped to a discrete time axis for the join purpose
TimeKey = bin(Timestamp, lookupBin)
| join kind=inner
(
T
| where EventType == 'B'
| project SessionId, End=Timestamp,
// TimeKey on the right side of the join - emulates event 'B' appearing several times
// as if it was 'replicated'
TimeKey = range(bin(Timestamp-lookupWindow, lookupBin),
bin(Timestamp, lookupBin),
lookupBin)
// 'mv-expand' translates the TimeKey array range into a column
| mv-expand TimeKey to typeof(datetime)
) on SessionId, TimeKey
| where (End - Start) between (0min .. lookupWindow)
| project SessionId, Start, End
Referência de consulta passível de execução (com a tabela indicada)
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
Saída
SessionId | Iniciar | Fim |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
Consulta de dados de 5 M
A consulta seguinte emula um conjunto de dados de registos de 5 M e ~1 M IDs e executa a consulta com a técnica descrita acima.
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
Saída
de palavras |
---|
3344 |
Comentários
https://aka.ms/ContentUserFeedback.
Brevemente: Ao longo de 2024, vamos descontinuar progressivamente o GitHub Issues como mecanismo de feedback para conteúdos e substituí-lo por um novo sistema de feedback. Para obter mais informações, veja:Submeter e ver comentários