Share via


掃描運算子

掃描資料、比對和組建以述詞為基礎的序列。

系統會根據運算子步驟中所定義的述詞來判定比對記錄。 述詞可取決於先前步驟所產生的狀態。 比對記錄的輸出是由運算子步驟中所定義的輸入記錄和指派所決定。

語法

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

ColumnDeclarations 語法

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

StepDefinition 語法

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

深入瞭解 語法慣例

參數

名稱 類型 必要 Description
T string ✔️ 輸入表格式來源。
MatchIdColumnName string 在掃描執行過程中附加至輸出之型 long 別的數據行名稱。 指出記錄相符專案的 0 型索引。
ColumnDeclarations string 宣告 T 架構的延伸模組。這些步驟中會指派這些數據行的值。 如果未指派,則會傳回 DefaultValue 。 除非另有指定, 否則 DefaultValuenull
StepName string ✔️ 用來參考掃描條件和指派狀態中的值。 步驟名稱必須是唯一的。
條件 string ✔️ 評估為 truefalse 的表示式,定義輸入中的哪些記錄符合步驟。 當條件為 true 步驟狀態或上一個步驟的狀態時,記錄會比對步驟。
指派 string 當記錄符合步驟時,指派給對應數據行的純量表達式。
output string 控制重複相符專案上步驟的輸出邏輯。 all 會輸出所有符合步驟的記錄、 last 只輸出步驟一系列重複比對中的最後一筆記錄,而且 none 不會輸出符合步驟的記錄。 預設為 all

傳回

從輸入到步驟的各記錄相符項目的記錄。 輸出的結構描述是在 declare 子句中使用資料行擴充的來源結構描述。

掃描邏輯

scan 會逐記錄仔細檢查已序列化的輸入資料,將每一筆記錄與每個步驟的條件進行比較,同時考慮每個步驟的目前狀態。

狀態

運算子的基礎狀態 scan 可以視為具有每個 step數據列的數據表。 每個步驟都會使用所有先前步驟和目前步驟中的最新數據行值和宣告的變數來維護自己的狀態。 如果相關,它也會保存進行中序列的比對標識符。

如果掃描運算符具有名為 s_1s_2...、... s_nn 個步驟,則步驟s_k的狀態會對應至s_1s_2...、s_kStepNameColumnName 格式是用來參考狀態中的值。 例如, s_2.col1 會參考 col1 屬於s_k狀態之步驟 s_2 的數據 。 如需詳細的範例,請參閱 掃描邏輯逐步解說

每當掃描的輸入記錄符合步驟時,狀態就會啟動空白並更新。 當目前步驟的狀態為無空時,步驟稱為具有 作用中序列

比對邏輯

每個輸入記錄都會以反向順序評估所有步驟,從最後一個步驟到第一個步驟。 當記錄 r 針對某些步驟 s_k進行評估時,會套用下列邏輯:

  • 檢查 1:如果上一個步驟的狀態 (s_k-1) 為 nonempty,且 r 符合s_k的條件,則會發生比對。 比對會導致下列動作:

    1. 已清除 s_k 的狀態。
    2. s_k-1 的狀態會升階為s_k的狀態。
    3. 計算 s_k 指派並擴充 r
    4. 擴充 r 會新增至輸出和 s_k的狀態。

    注意

    如果 Check 1 會產生相符專案,則會忽略 Check 2 ,而 r 會繼續針對 s_k-1 進行評估。

  • 檢查 2:如果s_k的狀態具有作用中序列或s_k是第一個步驟,且 r 符合s_k的條件,則會發生相符專案。 比對會導致下列動作:

    1. 計算 s_k 指派並擴充 r
    2. 表示 s_k 狀態 s_k 的值會取代為擴充 r 的值。
    3. 如果 s_k 定義為 output=all,則會將擴充 r 新增至輸出。
    4. 如果 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 1
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 會為每個相異比對指派唯一值, (會話) 掃描。 另請注意此範例中這兩個步驟的特殊用途,inSessiontrue 作為條件,因此其會從輸入中擷取並輸出所有記錄,而 endSession 會從目前相符項目的 sessionStart 值中擷取超過 30 分鐘的記錄。 endSession 步驟具有 output=none,代表其不會產生輸出記錄。 endSession 步驟是用來將目前相符項目的狀態從 inSession 向前移至 endSession,讓新的相符項目 (工作階段) 開始 (從目前的記錄開始)。

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

開始與停止之間的事件

尋找在 5 分鐘內事件 Start 和事件 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 Stop 0
00:08:00 開始 1
00:11:00 E 1
00:12:00 Stop 1

計算事件的自訂漏斗圖

State 計算序列 Hail ->Tornado ->Thunderstorm Wind 的漏斗圖完成情況,並在事件之間的時間上使用自訂閾值 (1h 內的 Tornado2h 內的 Thunderstorm Wind)。 此範例類似於 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
Hail 50
龍捲風 34
Thunderstorm Wind 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 視為每個步驟有一個數據列的數據表,其中每個步驟都有自己的狀態。 此狀態包含所有先前步驟和目前步驟中數據行和宣告變數的最新值。 若要深入瞭解,請參閱 狀態

在此範例中,狀態可以使用下表來表示:

步驟 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 會捨棄,而不會影響狀態或輸出。

狀態:

步驟 m_id s1.Ts s1.事件 s2.Ts s2.事件 s3.Ts s3.事件
s1 X X X X
s2 X X
S3

記錄 2

Ts 事件
1m "Start"

在每個步驟記錄評估:

  • s3檢查 1 不會傳遞,因為 狀態 s2 是空的, 而且檢查 2 不會通過,因為 s3 缺少作用中序列。
  • s2檢查 1 不會傳遞,因為 狀態 s1 是空的, 而且檢查 2 不會通過,因為 s2 缺少作用中序列。
  • s1檢查 1 無關,因為沒有上一個步驟。 檢查 2 已通過,因為記錄符合 的條件 Event == "Start"。 此比對會起始新的序列,並 m_id 指派 。 記錄 2 及其 m_id (0) 會新增至狀態和輸出。

狀態:

步驟 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 事件
2m "B"

在每個步驟記錄評估:

  • s3檢查 1 不會傳遞,因為 狀態 s2 是空的, 而且檢查 2 不會通過,因為 s3 缺少作用中序列。
  • s2檢查 1 會傳遞,因為 的狀態 s1 為無空,且記錄符合 的條件 Ts - s1.Ts < 5m。 此比對會導致 清除的狀態 s1 ,並將中的 s1 序列升階為 s2記錄 3 及其 m_id (0) 會新增至狀態和輸出。
  • s1檢查 1 無關,因為沒有上一個步驟,而且 不會傳遞 Check 2 ,因為記錄不符合 的條件 Event == "Start"

狀態:

步驟 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 事件
3m "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 無關,因為沒有上一個步驟,而且 不會傳遞 Check 2 ,因為記錄不符合 的條件 Event == "Start"

狀態:

步驟 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"

狀態:

步驟 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 未通過,因為沒有上一個步驟,而且 不會通過 Check 2 ,因為它不符合 的條件 Event == "Start"記錄 6 會捨棄,而不會影響狀態或輸出。

狀態:

步驟 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"。 此比對會使用新的 起始新的m_id序列s1記錄 7 及其 m_id (1) 會新增至狀態和輸出。

狀態:

步驟 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 不相關,因為沒有上一個步驟, 而且不會通過 Check 2 ,因為記錄不符合 的條件 Event == "Start"

狀態:

步驟 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"。 此比對會以新的 m_id起始新的s1序列。

狀態:

步驟 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 Stop 0
00:08:00 開始 1
00:11:00 E 1
00:12:00 Stop 1