掃描運算子
適用於:✅Microsoft網狀架構✅Azure 數據✅總管 Azure 監視器✅Microsoft Sentinel
根據述詞掃描數據、比對和建置序列。
比對記錄是根據運算符步驟中定義的述詞來決定。 述詞可以取決於先前步驟所產生的狀態。 比對記錄的輸出取決於運算符步驟中定義的輸入記錄和指派。
語法
T [ MatchIdColumnName ] [ declare
=
(
with_match_id
ColumnDeclarations )
] with
(
StepDefinitions | scan
)
ColumnDeclarations 語法
ColumnName :
ColumnType[=
DefaultValue ] [,
... ]
StepDefinition 語法
step
StepName [ output
| = none
all
last
| ] :
Condition [ Column =
Assignment [,
=>
... ] ];
深入瞭解 語法慣例。
參數
姓名 | 類型 | 必要 | 描述 |
---|---|---|---|
T | string |
✔️ | 輸入表格式來源。 |
MatchIdColumnName | string |
在掃描執行時附加至輸出之類型的數據 long 行名稱。 指出記錄相符專案的 0 型索引。 |
|
ColumnDeclarations | string |
宣告 T 架構的延伸模組。這些步驟中會指派這些數據行的值。 如果未指派,則會 傳回DefaultValue 。 除非另有指定, 否則 DefaultValue 為 null 。 |
|
StepName | string |
✔️ | 用來參考掃描條件和指派狀態中的值。 步驟名稱必須是唯一的。 |
Condition | string |
✔️ | 評估為 true 或 false 的表示式,定義輸入中的哪些記錄符合步驟。 當條件為 true 步驟狀態或上一個步驟的狀態時,記錄會比對步驟。 |
指派 | string |
當記錄符合步驟時,指派給對應數據行的純量表達式。 | |
output |
string |
在重複的相符專案上控制步驟的輸出邏輯。 all 輸出符合步驟的所有記錄、 last 只輸出步驟一系列重複比對中的最後一筆記錄,而且 none 不會輸出符合步驟的記錄。 預設值為 all 。 |
傳回
從輸入到步驟之記錄的每個相符項目記錄。 輸出的架構是以 子句中的數據 declare
行擴充的來源架構。
掃描邏輯
scan
會逐筆記錄逐一串行化輸入數據,比較每個記錄與每個步驟的條件,同時考慮到每個步驟的目前狀態。
州/省
運算子的基礎狀態 scan
可以視為具有每個 step
數據列的數據表。 每個步驟都會使用數據行的最新值,以及先前所有步驟和目前步驟中宣告的變數,維護自己的狀態。 如果相關,它也會保留進行中序列的相符標識符。
如果掃描運算符具有名為 s_1、s_2...、...、s_n的 n 個步驟,則步驟s_k會在其狀態中具有與s_1、s_2、...、s_k對應的 k 記錄。 StepName。ColumnName 格式是用來參考狀態中的值。 例如,s_2.col1
會參考col1
屬於s_k狀態之步驟s_2的數據行。 如需詳細範例,請參閱 掃描邏輯逐步解說。
每當掃描的輸入記錄符合步驟時,狀態就會啟動空白並更新。 當目前步驟的狀態為非空白時,步驟稱為具有 作用中序列。
比對邏輯
每個輸入記錄都會根據從最後一個步驟到第一個步驟的所有反向順序進行評估。 當記錄 r 針對某些步驟 s_k進行評估時,會套用下列邏輯:
檢查 1:如果上一個步驟 (s_k-1) 的狀態是空的,且 r 符合 s_k 的條件,則會發生相符專案。 比對會導致下列動作:
- 清除s_k的狀態。
- s_k-1 的狀態會升級為成為s_k的狀態。
- 計算s_k指派並擴充 r。
- 擴充 r 會新增至輸出和s_k的狀態。
注意
如果 Check 1 會產生相符專案,則會忽略 Check 2,r 會繼續針對 s_k-1 進行評估。
檢查 2:如果s_k的狀態為使用中序列或s_k是第一個步驟,而 r 符合 s_k 的條件,則會發生比對。 比對會導致下列動作:
- 計算s_k指派並擴充 r。
- 表示s_k狀態s_k的值會取代為擴充 r 的值。
- 如果 s_k 定義為
output=all
,則會將擴充 r 新增至輸出。 - 如果 s_k 是第一個步驟,就會開始新的序列,而比對標識符會依
1
增加。 這隻會影響使用 時的with_match_id
輸出。
檢查s_k完成後,r 會繼續評估 s_k-1。
如需此邏輯的詳細範例,請參閱 掃描邏輯逐步解說。
範例
累計總和
計算輸入數據行的累計總和。 此範例的結果相當於使用 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;
)
輸出
x | cumulative_x |
---|---|
1 | 7 |
2 | 3 |
3 | 6 |
4 | 10 |
5 | 15 |
具有重設條件之多個數據行的累計總和
計算兩個輸入數據行的累計總和,每當累計總和達到10個以上時,將總和重設為當前記錄值。
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);
)
輸出
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 |
向前填入數據行
向前填入字串數據行。 每個空白值都會指派最後一個未見空值。
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);
)
輸出
Ts | 活動 | 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 |
會話標記
將輸入分割成會話:會話會在會話的第一個事件之後 30 分鐘結束,之後就會啟動新的會話。 請注意旗標的使用with_match_id
,這會為掃描的每個相異相符專案(會話)指派唯一值。 另請注意,在此範例中特別使用兩個步驟,具有 true
條件,inSession
因此它會從輸入擷取和輸出所有記錄,同時endSession
擷取目前相符專案值超過 30m sessionStart
的記錄。 步驟 endSession
表示 output=none
它不會產生輸出記錄。 步驟 endSession
是用來將目前相符專案的狀態從 inSession
前進到 endSession
,讓新的比對 (session) 從目前的記錄開始。
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;
)
輸出
Ts | 活動 | 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 |
開始和停止之間的事件
尋找事件 Start
與 5 分鐘內發生之事件之間的所有事件 Stop
序列。 為每個序列指派相符標識碼。
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;
)
輸出
Ts | 活動 | m_id |
---|---|---|
00:01:00 | 啟動 | 0 |
00:02:00 | B | 0 |
00:03:00 | D | 0 |
00:04:00 | 停止 | 0 |
00:08:00 | 啟動 | 1 |
00:11:00 | E | 1 |
00:12:00 | 停止 | 1 |
計算事件的自定義漏鬥圖
計算序列Hail
的漏鬥完成 -Tornado
>Thunderstorm Wind
> 依據State
事件之間的時間自定義臨界值(Tornado
在 1h
內和Thunderstorm Wind
內)。2h
此範例與 funnel_sequence_completion外掛程式類似,但允許更大的彈性。
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
輸出
EventType | dcount_State |
---|---|
冰雹 | 50 |
龍捲風 | 34 |
雷暴風 | 32 |
掃描邏輯逐步解說
本節示範使用啟動與停止之間事件範例的逐步解說來示範掃描邏輯:
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;
)
狀態
請將 運算符的狀態視為具有每個步驟數據列的 scan
數據表,其中每個步驟都有自己的狀態。 此狀態包含所有先前步驟和目前步驟中數據行和宣告變數的最新值。 若要深入瞭解,請參閱 狀態。
在此範例中,狀態可以使用下表來表示:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | X | X | X | X | |||
s2 | X | X | |||||
S3 |
“X” 表示特定欄位與此步驟無關。
比對邏輯
本節會透過數據表的每個記錄遵循比對Events
邏輯,說明每個步驟的狀態和輸出轉換。
注意
輸入記錄會根據從最後一個步驟() 到第一個步驟的s3
反向順序來評估步驟。s1
記錄 1
Ts | 活動 |
---|---|
0m | "A" |
記錄每個步驟的評估:
s3
: 檢查 1 不會通過,因為 的狀態s2
是空的,而且 檢查 2 未通過,因為s3
缺少作用中的序列。s2
: 檢查 1 不會通過,因為 的狀態s1
是空的,而且 檢查 2 未通過,因為s2
缺少作用中的序列。s1
: 檢查 1 無關緊要,因為沒有上一個步驟。 檢查 2 未通過,因為記錄不符合 的條件Event == "Start"
。 記錄 1 會捨棄,而不會影響狀態或輸出。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | X | X | X | X | |||
s2 | X | X | |||||
S3 |
記錄 2
Ts | 活動 |
---|---|
1 分鐘 | “Start” |
記錄每個步驟的評估:
s3
: 檢查 1 不會通過,因為 的狀態s2
是空的,而且 檢查 2 未通過,因為s3
缺少作用中的序列。s2
: 檢查 1 不會通過,因為 的狀態s1
是空的,而且 檢查 2 未通過,因為s2
缺少作用中的序列。s1
: 檢查 1 無關緊要,因為沒有上一個步驟。 檢查 2 已通過,因為記錄符合 的條件Event == "Start"
。 此比對會起始新的序列,並m_id
指派 。 記錄 2 及其m_id
(0
) 會新增至狀態和輸出。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | 0 | 00:01:00 | “Start” | X | X | X | X |
s2 | X | X | |||||
S3 |
記錄 3
Ts | 活動 |
---|---|
2 分 | "B" |
記錄每個步驟的評估:
s3
: 檢查 1 不會通過,因為 的狀態s2
是空的,而且 檢查 2 未通過,因為s3
缺少作用中的序列。s2
: 檢查 1 是傳遞的,因為 的狀態s1
是空的,且記錄符合 的條件Ts - s1.Ts < 5m
。 此比對會導致 清除的狀態s1
,並將中的s1
序列升階為s2
。 記錄 3 及其m_id
(0
) 會新增至狀態和輸出。s1
: 檢查 1 無關緊要,因為沒有上一個步驟,而且 檢查 2 未通過,因為記錄不符合 的條件Event == "Start"
。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | X | X | X | X | |||
s2 | 0 | 00:01:00 | “Start” | 00:02:00 | "B" | X | X |
S3 |
記錄 4
Ts | 活動 |
---|---|
3 個月 | "D" |
記錄每個步驟的評估:
s3
: 檢查 1 未通過,因為記錄不符合 的條件Event == "Stop"
,而且 檢查 2 未通過,因為s3
缺少使用中序列。s2
: 檢查 1 未通過,因為 的狀態s1
是空的。 它會通過 Check 2 ,因為它符合 的條件Ts - s1.Ts < 5m
。 記錄 4 及其m_id
(0
) 會新增至狀態和輸出。 此記錄中的值會覆寫 和s2.Event
的先前狀態值s2.Ts
。s1
: 檢查 1 無關緊要,因為沒有上一個步驟,而且 檢查 2 未通過,因為記錄不符合 的條件Event == "Start"
。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | X | X | X | X | |||
s2 | 0 | 00:01:00 | “Start” | 00:03:00 | "D" | X | X |
S3 |
記錄 5
Ts | 活動 |
---|---|
4m | “Stop” |
記錄每個步驟的評估:
s3
: 檢查 1 是通過,因為s2
是空的,而且符合s3
的條件Event == "Stop"
。 此比對會導致 清除的狀態s2
,並將中的s2
序列升階為s3
。 記錄 5 及其m_id
(0
) 會新增至狀態和輸出。s2
: 檢查 1 不會通過,因為 的狀態s1
是空的,而且 檢查 2 未通過,因為s2
缺少作用中的序列。s1
: 檢查 1 無關緊要,因為沒有上一個步驟。 檢查 2 未通過,因為記錄不符合 的條件Event == "Start"
。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | X | X | X | X | |||
s2 | X | X | |||||
S3 | 0 | 00:01:00 | “Start” | 00:03:00 | "D" | 00:04:00 | “Stop” |
記錄 6
Ts | 活動 |
---|---|
6m | “C” |
記錄每個步驟的評估:
s3
:檢查 1 不會通過,因為 的狀態s2
是空的,而且檢查 2 未通過s3
,因為s3
不符合 的條件Event == "Stop"
。s2
: 檢查 1 不會通過,因為 的狀態s1
是空的,而且 檢查 2 未通過,因為s2
缺少作用中的序列。s1
: 檢查 1 未通過,因為沒有上一個步驟,而且 檢查 2 未通過,因為它不符合 的條件Event == "Start"
。 記錄 6 會捨棄,而不會影響狀態或輸出。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | X | X | X | X | |||
s2 | X | X | |||||
S3 | 0 | 00:01:00 | “Start” | 00:03:00 | "D" | 00:04:00 | “Stop” |
記錄 7
Ts | 活動 |
---|---|
8m | “Start” |
記錄每個步驟的評估:
s3
: 檢查 1 不會通過,因為 的狀態s2
是空的,而且 檢查 2 未通過,因為它不符合 的條件Event == "Stop"
。s2
: 檢查 1 不會通過,因為 的狀態s1
是空的,而且 檢查 2 未通過,因為s2
缺少作用中的序列。s1
: 檢查 1 未通過,因為沒有上一個步驟。 它會通過 Check 2 ,因為它符合 的條件Event == "Start"
。 此比對會使用新的 ,在 中s1
起始新的m_id
序列。 記錄 7 及其m_id
(1
) 會新增至狀態和輸出。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
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” |
注意
狀態中現在有兩個作用中序列。
記錄8
Ts | 活動 |
---|---|
11m | “E” |
記錄每個步驟的評估:
s3
: 檢查 1 不會通過,因為 的狀態s2
是空的,而且 檢查 2 未通過s3
,因為它不符合 的條件Event == "Stop"
。s2
: 檢查 1 是傳遞的,因為 的狀態s1
是空的,且記錄符合 的條件Ts - s1.Ts < 5m
。 此比對會導致 清除的狀態s1
,並將中的s1
序列升階為s2
。 記錄 8 及其m_id
(1
) 會新增至狀態和輸出。s1
: 檢查 1 無關緊要,因為沒有上一個步驟,而且 檢查 2 未通過,因為記錄不符合 的條件Event == "Start"
。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
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” |
記錄 9
Ts | 活動 |
---|---|
12m | “Stop” |
記錄每個步驟的評估:
s3
: 檢查 1 是通過,因為s2
是空的,而且符合s3
的條件Event == "Stop"
。 此比對會導致 清除的狀態s2
,並將中的s2
序列升階為s3
。 記錄 9 及其m_id
(1
) 會新增至狀態和輸出。s2
: 檢查 1 不會通過,因為 的狀態s1
是空的,而且 檢查 2 未通過,因為s2
缺少作用中的序列。s1
: 檢查 1 未通過,因為沒有上一個步驟。 它會通過 Check 2 ,因為它符合 的條件Event == "Start"
。 此比對會使用新的 ,在 中s1
起始新的m_id
序列。
州:
step | m_id | s1.Ts | s1.事件 | s2.Ts | s2.事件 | s3.Ts | s3.事件 |
---|---|---|---|---|---|---|---|
s1 | X | X | X | X | |||
s2 | X | X | |||||
S3 | 1 | 00:08:00 | “Start” | 00:11:00 | “E” | 00:12:00 | “Stop” |
最終輸出
Ts | 活動 | m_id |
---|---|---|
00:01:00 | 啟動 | 0 |
00:02:00 | B | 0 |
00:03:00 | D | 0 |
00:04:00 | 停止 | 0 |
00:08:00 | 啟動 | 1 |
00:11:00 | E | 1 |
00:12:00 | 停止 | 1 |