Partilhar via


scan operator

Applies to: ✅Microsoft FabricAzure Data ExplorerAzure MonitorMicrosoft Sentinel

Analisa dados, faz correspondências e cria sequências com base nos predicados.

Os registros correspondentes são determinados de acordo com predicados definidos nas etapas do operador. Um predicado pode depender do estado gerado pelas etapas anteriores. A saída para o registro correspondente é determinada pelo registro de entrada e atribuições definidas nas etapas do operador.

Syntax

T| scan [ with_match_id=MatchIdColumnName ] [ declare(ColumnDeclarations) ] with(StepDefinitions)

ColumnDeclarations syntax

ColumnName:ColumnType[=DefaultValue ] [, ... ]

StepDefinition syntax

step StepName [ output = all | last | none] :Condition [ =>Column=Assignment [, ... ] ] ;

Learn more about syntax conventions.

Parameters

Name Tipo Required Description
T string ✔️ A fonte tabular de entrada.
MatchIdColumnName string O nome de uma coluna do tipo long que é anexada à saída como parte da execução da verificação. Indica o índice baseado em 0 da correspondência para o registro.
ColumnDeclarations string Declares an extension to the schema of T. These columns are assigned values in the steps. If not assigned, the DefaultValue is returned. Unless otherwise specified, DefaultValue is null.
StepName string ✔️ Usado para referenciar valores no estado de verificação de condições e atribuições. O nome da etapa deve ser exclusivo.
Condition string ✔️ Uma expressão avaliada como true ou false que define quais registros da entrada correspondem à etapa. Um registro corresponde à etapa quando a condição é true com o estado da etapa ou com o estado da etapa anterior.
Assignment string Uma expressão escalar que é atribuída à coluna correspondente quando um registro corresponde a uma etapa.
output string Controla a lógica de saída da etapa em correspondências repetidas. all produz todos os registros correspondentes à etapa, last produz apenas o último registro de uma série de correspondências repetidas para a etapa e none não produz registros correspondentes à etapa. O padrão é all.

Returns

Um registro para cada partida de um registro da entrada para uma etapa. O esquema da saída é o esquema da fonte estendida com a coluna na cláusula declare.

Scan logic

scan analisa os dados de entrada serializados, registro por registro, comparando cada registro com a condição de cada etapa, levando em consideração o estado atual de cada etapa.

State

O estado subjacente do operador scan pode ser considerado como uma tabela com uma linha para cada step. Cada etapa mantém seu próprio estado com os valores mais recentes das colunas e variáveis declaradas de todas as etapas anteriores e da etapa atual. Se relevante, ele também mantém o ID de correspondência para a sequência em andamento.

If a scan operator has n steps named s_1, s_2, ..., s_n then step s_k would have k records in its state corresponding to s_1, s_2, ..., s_k. The StepName.ColumnName format is used to reference a value in the state. For instance, s_2.col1 would reference column col1 that belongs to step s_2 in the state of s_k. Para obter um exemplo detalhado, consulte o passo a passo da lógica de verificação .

O estado começa vazio e é atualizado sempre que um registro de entrada digitalizado corresponde a uma etapa. When the state of the current step is nonempty, the step is referred to as having an active sequence.

Matching logic

Cada registro de entrada é avaliado em relação a todas as etapas em ordem inversa, da última etapa à primeira. When a record r is evaluated against some step s_k, the following logic is applied:

  • Check 1: If the state of the previous step (s_k-1) is nonempty, and r meets the Condition of s_k, then a match occurs. A correspondência leva às seguintes ações:

    1. The state of s_k is cleared.
    2. The state of s_k-1 is promoted to become the state of s_k.
    3. The assignments of s_k are calculated and extend r.
    4. The extended r is added to the output and to the state of s_k.

    Note

    If Check 1 results in a match, Check 2 is disregarded, and r moves on to be evaluated against s_k-1.

  • Check 2: If the state of s_k has an active sequence or s_k is the first step, and r meets the Condition of s_k, then a match occurs. A correspondência leva às seguintes ações:

    1. The assignments of s_k are calculated and extend r.
    2. The values that represent s_k in the state of s_k are replaced with the values of the extended r.
    3. If s_k is defined as output=all, the extended r is added to the output.
    4. If s_k is the first step, a new sequence begins and the match ID increases by 1. Isso só afeta a saída quando with_match_id é usada.

Once the checks for s_k are complete, r moves on to be evaluated against s_k-1.

Para obter um exemplo detalhado dessa lógica, consulte o passo a passo da lógica de verificação .

Examples

O exemplo nesta seção mostra como usar a sintaxe para ajudá-lo a começar.

The examples in this article use publicly available tables in the help cluster, such as the StormEvents table in the Samples database.

The examples in this article use publicly available tables, such as the Weather table in the Weather analytics sample gallery. Talvez seja necessário modificar o nome da tabela na consulta de exemplo para corresponder à tabela em seu espaço de trabalho.

Cumulative sum

Calcule a soma cumulativa de uma coluna de entrada. The result of this example is equivalent to using row_cumsum().

range x from 1 to 5 step 1 
| scan declare (cumulative_x:long=0) with 
(
    step s1: true => cumulative_x = x + s1.cumulative_x;
)

Output

x cumulative_x
1 1
2 3
3 6
4 10
5 15

Soma cumulativa em várias colunas com uma condição de redefinição

Calcule a soma acumulada para duas colunas de entrada, redefina o valor da soma para o valor de registro atual sempre que a soma acumulada atingir 10 ou mais.

range x from 1 to 5 step 1
| extend y = 2 * x
| scan declare (cumulative_x:long=0, cumulative_y:long=0) with 
(
    step s1: true => cumulative_x = iff(s1.cumulative_x >= 10, x, x + s1.cumulative_x), 
                     cumulative_y = iff(s1.cumulative_y >= 10, y, y + s1.cumulative_y);
)

Output

x y cumulative_x cumulative_y
1 2 1 2
2 4 3 6
3 6 6 12
4 8 10 8
5 10 5 18

Preencher uma coluna

Preencha uma coluna de cadeia de caracteres. A cada valor vazio é atribuído o último valor não vazio visto.

let Events = datatable (Ts: timespan, Event: string) [
    0m, "A",
    1m, "",
    2m, "B",
    3m, "",
    4m, "",
    6m, "C",
    8m, "",
    11m, "D",
    12m, ""
]
;
Events
| sort by Ts asc
| scan declare (Event_filled: string="") with 
(
    step s1: true => Event_filled = iff(isempty(Event), s1.Event_filled, Event);
)

Output

Ts Event Event_filled
00:00:00 A A
00:01:00 A
00:02:00 B B
00:03:00 B
00:04:00 B
00:06:00 C C
00:08:00 C
00:11:00 D D
00:12:00 D

Sessions tagging

Divida a entrada em sessões: uma sessão termina 30 minutos após o primeiro evento da sessão, após o qual uma nova sessão começa. Note the use of with_match_id flag, which assigns a unique value for each distinct match (session) of scan. Also note the special use of two steps in this example, inSession has true as condition so it captures and outputs all the records from the input while endSession captures records that happen more than 30m from the sessionStart value for the current match. A etapa endSession tem output=none significa que não produz registros de saída. A etapa endSession é usada para avançar o estado da partida atual de inSession para endSession, permitindo que uma nova partida (sessão) comece, a partir do registro atual.

let Events = datatable (Ts: timespan, Event: string) [
    0m, "A",
    1m, "A",
    2m, "B",
    3m, "D",
    32m, "B",
    36m, "C",
    38m, "D",
    41m, "E",
    75m, "A"
]
;
Events
| sort by Ts asc
| scan with_match_id=session_id declare (sessionStart: timespan) with 
(
    step inSession: true => sessionStart = iff(isnull(inSession.sessionStart), Ts, inSession.sessionStart);
    step endSession output=none: Ts - inSession.sessionStart > 30m;
)

Output

Ts Event sessionStart session_id
00:00:00 A 00:00:00 0
00:01:00 A 00:00:00 0
00:02:00 B 00:00:00 0
00:03:00 D 00:00:00 0
00:32:00 B 00:32:00 1
00:36:00 C 00:32:00 1
00:38:00 D 00:32:00 1
00:41:00 E 00:32:00 1
01:15:00 A 01:15:00 2

Calculando a duração da sessão por usuário

Calcule a hora de início, a hora de término e a duração da sessão de cada usuário usando o scan operador. Uma sessão é definida como um período entre o login de um usuário e o logout subsequente. Ao combinar partition e scan com e output=none, output=all esse padrão garante que uma única linha seja retornada por sessão (ou seja, por par de login/logout), em vez de uma linha por evento.

A lógica funciona por:

  • Na etapa s1: Capturando o carimbo de data/hora de login usando uma etapa de verificação com output=none
  • Na etapa s2: Emitindo uma linha somente quando um logout correspondente é encontrado usando output=all
let LogsEvents = datatable(Timestamp:datetime, userID:int, EventType:string)
[
    datetime(2024-05-28 08:15:23), 1, "login",
    datetime(2024-05-28 08:30:15), 2, "login",
    datetime(2024-05-28 09:10:27), 3, "login",
    datetime(2024-05-28 12:30:45), 1, "logout",
    datetime(2024-05-28 11:45:32), 2, "logout",
    datetime(2024-05-28 13:25:19), 3, "logout"
];
LogsEvents
| sort by userID, Timestamp
| partition hint.strategy=native by userID (
    sort by Timestamp asc 
    | scan declare (start: datetime, end: datetime, sessionDuration: timespan) with (
        step s1 output=none: EventType == "login" => start = Timestamp;
        step s2 output=all: EventType == "logout" => start = s1.start, end = Timestamp, sessionDuration = Timestamp - s1.start;
    )
)
| project start, end, userID, sessionDuration

Output

userID start end sessionDuration
1 2024-05-28 08:15:23.0000 2024-05-28 12:30:45.0000 04:15:22
3 2024-05-28 09:10:27.0000 2024-05-28 13:25:19.0000 04:14:52
2 2024-05-28 08:30:15.0000 2024-05-28 11:45:32.0000 03:15:17

Eventos entre Iniciar e Parar

Encontre todas as sequências de eventos entre o Start de eventos e os Stop de eventos que ocorrem dentro de 5 minutos. Atribua um ID de correspondência para cada sequência.

let Events = datatable (Ts: timespan, Event: string) [
    0m, "A",
    1m, "Start",
    2m, "B",
    3m, "D",
    4m, "Stop",
    6m, "C",
    8m, "Start",
    11m, "E",
    12m, "Stop"
]
;
Events
| sort by Ts asc
| scan with_match_id=m_id with 
(
    step s1: Event == "Start";
    step s2: Event != "Start" and Event != "Stop" and Ts - s1.Ts <= 5m;
    step s3: Event == "Stop" and Ts - s1.Ts <= 5m;
)

Output

Ts Event m_id
00:01:00 Start 0
00:02:00 B 0
00:03:00 D 0
00:04:00 Stop 0
00:08:00 Start 1
00:11:00 E 1
00:12:00 Stop 1

Calcular um funil personalizado de eventos

Calcule uma conclusão de funil da sequência Hail ->Tornado ->Thunderstorm Wind por State com limites personalizados nos tempos entre os eventos (Tornado dentro de 1h e Thunderstorm Wind dentro de 2h). This example is similar to the funnel_sequence_completion plugin, but allows greater flexibility.

StormEvents
| partition hint.strategy=native by State 
    (
    sort by StartTime asc
    | scan with 
    (
        step hail: EventType == "Hail";
        step tornado: EventType == "Tornado" and StartTime - hail.StartTime <= 1h;
        step thunderstormWind: EventType == "Thunderstorm Wind" and StartTime - tornado.StartTime <= 2h;
    )
    )
| summarize dcount(State) by EventType

Output

EventType dcount_State
Hail 50
Tornado 34
Thunderstorm Wind 32

Passo a passo da lógica de varredura

This section demonstrates the scan logic using a step-by-step walkthrough of the Events between start and stop example:

let Events = datatable (Ts: timespan, Event: string) [
    0m, "A",
    1m, "Start",
    2m, "B",
    3m, "D",
    4m, "Stop",
    6m, "C",
    8m, "Start",
    11m, "E",
    12m, "Stop"
]
;
Events
| sort by Ts asc
| scan with_match_id=m_id with 
(
    step s1: Event == "Start";
    step s2: Event != "Start" and Event != "Stop" and Ts - s1.Ts <= 5m;
    step s3: Event == "Stop" and Ts - s1.Ts <= 5m;
)

Output

Ts Event m_id
00:01:00 Start 0
00:02:00 B 0
00:03:00 D 0
00:04:00 Stop 0
00:08:00 Start 1
00:11:00 E 1
00:12:00 Stop 1

The state

Pense no estado do operador scan como uma tabela com uma linha para cada etapa, na qual cada etapa tem seu próprio estado. Esse estado contém os valores mais recentes das colunas e variáveis declaradas de todas as etapas anteriores e da etapa atual. To learn more, see State.

Neste exemplo, o estado pode ser representado com a seguinte tabela:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 X X
s3

O "X" indica que um campo específico é irrelevante para essa etapa.

A lógica de correspondência

This section follows the matching logic through each record of the Events table, explaining the transformation of the state and output at each step.

Note

Um registro de entrada é avaliado em relação às etapas em ordem inversa, da última etapa (s3) para a primeira etapa (s1).

Record 1

Ts Event
0m "A"

Registar a avaliação em cada etapa:

  • s3: Check 1 isn't passed because the state of s2 is empty, and Check 2 isn't passed because s3 lacks an active sequence.
  • s2: Check 1 isn't passed because the state of s1 is empty, and Check 2 isn't passed because s2 lacks an active sequence.
  • s1: Check 1 is irrelevant because there's no previous step. Check 2 isn't passed because the record doesn't meet the condition of Event == "Start". Record 1 is discarded without affecting the state or output.

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 X X
s3

Record 2

Ts Event
1m "Start"

Registar a avaliação em cada etapa:

  • s3: Check 1 isn't passed because the state of s2 is empty, and Check 2 isn't passed because s3 lacks an active sequence.
  • s2: Check 1 isn't passed because the state of s1 is empty, and Check 2 isn't passed because s2 lacks an active sequence.
  • s1: Check 1 is irrelevant because there's no previous step. Check 2 is passed because the record meets the condition of Event == "Start". Essa correspondência inicia uma nova sequência e o m_id é atribuído. Record 2 and its m_id (0) are added to the state and the output.

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 0 00:01:00 "Start" X X X X
s2 X X
s3

Record 3

Ts Event
2m "B"

Registar a avaliação em cada etapa:

  • s3: Check 1 isn't passed because the state of s2 is empty, and Check 2 isn't passed because s3 lacks an active sequence.
  • s2: Check 1 is passed because the state of s1 is nonempty and the record meets the condition of Ts - s1.Ts < 5m. Essa correspondência faz com que o estado de s1 seja limpo e a sequência em s1 seja promovida para s2. Record 3 and its m_id (0) are added to the state and the output.
  • s1: Check 1 is irrelevant because there's no previous step, and Check 2 isn't passed because the record doesn't meet the condition of Event == "Start".

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 0 00:01:00 "Start" 00:02:00 "B" X X
s3

Record 4

Ts Event
3m "D"

Registar a avaliação em cada etapa:

  • s3: Check 1 isn't passed because the record doesn't meet the condition of Event == "Stop", and Check 2 isn't passed because s3 lacks an active sequence.
  • s2: Check 1 isn't passed because the state of s1 is empty. it passes Check 2 because it meets the condition of Ts - s1.Ts < 5m. Record 4 and its m_id (0) are added to the state and the output. Os valores desse registro substituem os valores de estado anteriores para s2.Ts e s2.Event.
  • s1: Check 1 is irrelevant because there's no previous step, and Check 2 isn't passed because the record doesn't meet the condition of Event == "Start".

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 0 00:01:00 "Start" 00:03:00 "D" X X
s3

Record 5

Ts Event
4m "Stop"

Registar a avaliação em cada etapa:

  • s3: Check 1 is passed because s2 is nonempty and it meets the s3 condition of Event == "Stop". Essa correspondência faz com que o estado de s2 seja limpo e a sequência em s2 seja promovida para s3. Record 5 and its m_id (0) are added to the state and the output.
  • s2: Check 1 isn't passed because the state of s1 is empty, and Check 2 isn't passed because s2 lacks an active sequence.
  • s1: Check 1 is irrelevant because there's no previous step. Check 2 isn't passed because the record doesn't meet the condition of Event == "Start".

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 X X
s3 0 00:01:00 "Start" 00:03:00 "D" 00:04:00 "Stop"

Record 6

Ts Event
6m "C"

Registar a avaliação em cada etapa:

  • s3: Check 1 isn't passed because the state of s2 is empty, and Check 2 isn't passed because s3 doesn't meet the s3 condition of Event == "Stop".
  • s2: Check 1 isn't passed because the state of s1 is empty, and Check 2 isn't passed because s2 lacks an active sequence.
  • s1: Check 1 isn't passed because there's no previous step, and Check 2 isn't passed because it doesn't meet the condition of Event == "Start". Record 6 is discarded without affecting the state or output.

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 X X
s3 0 00:01:00 "Start" 00:03:00 "D" 00:04:00 "Stop"

Record 7

Ts Event
8m "Start"

Registar a avaliação em cada etapa:

  • s3: Check 1 isn't passed because the state of s2 is empty, and Check 2 isn't passed because it doesn't meet the condition of Event == "Stop".
  • s2: Check 1 isn't passed because the state of s1 is empty, and Check 2 isn't passed because s2 lacks an active sequence.
  • s1: Check 1 isn't passed because there's no previous step. it passes Check 2 because it meets the condition of Event == "Start". Esta partida inicia uma nova sequência em s1 com um novo m_id. Record 7 and its m_id (1) are added to the state and the output.

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 1 00:08:00 "Start" X X X X
s2 X X
s3 0 00:01:00 "Start" 00:03:00 "D" 00:04:00 "Stop"

Note

Agora há duas sequências ativas no estado.

Record 8

Ts Event
11m "E"

Registar a avaliação em cada etapa:

  • s3: Check 1 isn't passed because the state of s2 is empty, and Check 2 isn't passed because it doesn't meet the s3 condition of Event == "Stop".
  • s2: Check 1 is passed because the state of s1 is nonempty and the record meets the condition of Ts - s1.Ts < 5m. Essa correspondência faz com que o estado de s1 seja limpo e a sequência em s1 seja promovida para s2. Record 8 and its m_id (1) are added to the state and the output.
  • s1: Check 1 is irrelevant because there's no previous step, and Check 2 isn't passed because the record doesn't meet the condition of Event == "Start".

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 1 00:08:00 "Start" 00:11:00 "E" X X
s3 0 00:01:00 "Start" 00:03:00 "D" 00:04:00 "Stop"

Record 9

Ts Event
12m "Stop"

Registar a avaliação em cada etapa:

  • s3: Check 1 is passed because s2 is nonempty and it meets the s3 condition of Event == "Stop". Essa correspondência faz com que o estado de s2 seja limpo e a sequência em s2 seja promovida para s3. Record 9 and its m_id (1) are added to the state and the output.
  • s2: Check 1 isn't passed because the state of s1 is empty, and Check 2 isn't passed because s2 lacks an active sequence.
  • s1: Check 1 isn't passed because there's no previous step. it passes Check 2 because it meets the condition of Event == "Start". Esta partida inicia uma nova sequência em s1 com um novo m_id.

State:

step m_id s1.Ts s1.Event s2.Ts s2.Event s3.Ts s3.Event
s1 X X X X
s2 X X
s3 1 00:08:00 "Start" 00:11:00 "E" 00:12:00 "Stop"

Final output

Ts Event m_id
00:01:00 Start 0
00:02:00 B 0
00:03:00 D 0
00:04:00 Stop 0
00:08:00 Start 1
00:11:00 E 1
00:12:00 Stop 1