Applies to: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
述語に基づいてデータをスキャンし、照合し、シーケンスを構築します。
一致するレコードは、演算子のステップで定義されている述語に従って決まります。 述語は、前のステップで生成された状態によって異なる場合があります。 一致するレコードの出力は、入力レコードと、演算子のステップで定義されている割り当てによって決まります。
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 | タイプ | Required | Description |
|---|---|---|---|
| T | string |
✔️ | 入力表形式のソース。 |
| MatchIdColumnName | string |
スキャン実行の一部として出力に追加される long 型の列の名前。 レコードの一致の 0 から始まるインデックスを示します。 |
|
| 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 |
✔️ | 条件と割り当てのスキャン状態の値を参照するために使用されます。 ステップ名は一意である必要があります。 |
| Condition | string |
✔️ | ステップに一致する入力のレコードを定義する true または false に評価される式。 レコードは、条件がステップの状態または前のステップの状態と true されたときにステップと一致します。 |
| Assignment | string |
レコードがステップと一致したときに対応する列に割り当てられるスカラー式。 | |
output |
string |
繰り返し一致するステップの出力ロジックを制御します。
all は、ステップに一致するすべてのレコードを出力 last 、ステップに対して一連の繰り返し一致の最後のレコードのみを出力し、 none はステップに一致するレコードを出力しません。 既定値は、all です。 |
Returns
入力からステップへのレコードが一致するたびに 1 つのレコード。 出力のスキーマは、declare 句の列で拡張されたソースのスキーマです。
Scan logic
scan は、各ステップの現在の状態を考慮しながら、シリアル化された入力データをレコードごとに処理し、各レコードを各ステップと比較していきます。
State
scan演算子の基になる状態は、各stepの行を含むテーブルと考えることができます。 各ステップは、列の最新の値と、前のすべてのステップと現在のステップから宣言された変数を使用して、独自の状態を維持します。 関連する場合は、進行中のシーケンスの一致 ID も保持されます。
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. 詳細な例については、 scan ロジックのチュートリアルを参照してください。
状態は空になり、スキャンされた入力レコードがステップと一致するたびに更新されます。 When the state of the current step is nonempty, the step is referred to as having an active sequence.
Matching logic
各入力レコードは、最後のステップから最初のステップまで、すべてのステップに対して逆の順序で評価されます。 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. 一致すると、次のアクションが実行されます。
- The state of s_k is cleared.
- The state of s_k-1 is promoted to become the state of s_k.
- The assignments of s_k are calculated and extend r.
- 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. 一致すると、次のアクションが実行されます。
- The assignments of s_k are calculated and extend r.
- The values that represent s_k in the state of s_k are replaced with the values of the extended r.
- If s_k is defined as
output=all, the extended r is added to the output. - If s_k is the first step, a new sequence begins and the match ID increases by
1. これは、with_match_idが使用されている場合にのみ出力に影響します。
Once the checks for s_k are complete, r moves on to be evaluated against s_k-1.
このロジックの詳細な例については、 scan ロジックのチュートリアルを参照してください。
Examples
このセクションの例では、構文を使用して作業を開始する方法を示します。
The examples in this article use publicly available tables in the help cluster, such as the
StormEventstable in the Samples database.
The examples in this article use publicly available tables, such as the
Weathertable in the Weather analytics sample gallery. ワークスペース内のテーブルと一致するように、クエリ例のテーブル名を変更する必要がある場合があります。
Cumulative sum
入力列の累積合計を計算します。 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 |
リセット条件を持つ複数の列の累積合計
2 つの入力列の累積合計を計算し、累積合計が 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);
)
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 |
列を順方向に埋める
文字列の列を順方向に埋めます。 各空の値には、最後に表示された空でない値が割り当てられます。
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
入力をセッションに分割します。セッションは、最初のセッション イベントから 30 分後に終了し、その後、新しいセッションが開始されます。 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.
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;
)
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 |
ユーザーごとのセッション長の計算
scan演算子を使用して、各ユーザーのセッションのセッション開始時刻、終了時刻、および期間を計算します。 セッションは、ユーザーのログインと後続のログアウトの間の期間として定義されます。 このパターンでは、 partition と scan を output=none と output=allと組み合わせることで、 イベントごとの行ではなく、セッションごとに 1 つの行 (ログイン/ログアウト ペアごと) が確実に返されます。
ロジックは次の方法で動作します。
- 手順 s1: スキャン ステップを使用してログイン タイムスタンプをキャプチャする
output=none - 手順 s2: 次を使用して、一致するログアウトが見つかった場合にのみ行を出力する
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 |
開始と終了の間のイベント
イベント Start とイベント Stop の間で、5 分以内に発生するイベントのシーケンスをすべて検索します。 各シーケンスに一致 ID を割り当てます。
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 |
イベントのカスタム ファネルを計算する
イベント間の時間に関するカスタムしきい値 (Hail 以内の > および Tornado 以内の >) を使用して、Thunderstorm Wind ごとに State -Tornado1h -Thunderstorm Wind2h というシーケンスのファネル完了率を計算します。 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 |
スキャン ロジックのチュートリアル
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
scan演算子の状態は、各ステップの行を含むテーブルと考えてください。各ステップには独自の状態があります。 この状態には、前のすべての手順と現在のステップの列と宣言された変数の最新の値が含まれます。 To learn more, see State.
この例では、状態は次の表で表すことができます。
| ステップ | m_id | s1.Ts | s1.Event | s2.Ts | s2.Event | s3.Ts | s3.Event |
|---|---|---|---|---|---|---|---|
| s1 | X | X | X | X | |||
| s2 | X | X | |||||
| s3 |
"X" は、特定のフィールドがそのステップとは無関係であることを示します。
一致するロジック
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
入力レコードは、最後のステップ (s3) から最初のステップ (s1) まで、ステップに対して逆の順序で評価されます。
Record 1
| Ts | Event |
|---|---|
| 0m | "A" |
各ステップで評価を記録します。
-
s3: Check 1 isn't passed because the state ofs2is empty, and Check 2 isn't passed becauses3lacks an active sequence. -
s2: Check 1 isn't passed because the state ofs1is empty, and Check 2 isn't passed becauses2lacks 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 ofEvent == "Start". Record 1 is discarded without affecting the state or output.
State:
| ステップ | 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" |
各ステップで評価を記録します。
-
s3: Check 1 isn't passed because the state ofs2is empty, and Check 2 isn't passed becauses3lacks an active sequence. -
s2: Check 1 isn't passed because the state ofs1is empty, and Check 2 isn't passed becauses2lacks an active sequence. -
s1: Check 1 is irrelevant because there's no previous step. Check 2 is passed because the record meets the condition ofEvent == "Start". この一致によって新しいシーケンスが開始され、m_idが割り当てられます。 Record 2 and itsm_id(0) are added to the state and the output.
State:
| ステップ | 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" |
各ステップで評価を記録します。
-
s3: Check 1 isn't passed because the state ofs2is empty, and Check 2 isn't passed becauses3lacks an active sequence. -
s2: Check 1 is passed because the state ofs1is nonempty and the record meets the condition ofTs - s1.Ts < 5m. この一致により、s1の状態がクリアされ、s1のシーケンスがs2に昇格されます。 Record 3 and itsm_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 ofEvent == "Start".
State:
| ステップ | 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" |
各ステップで評価を記録します。
-
s3: Check 1 isn't passed because the record doesn't meet the condition ofEvent == "Stop", and Check 2 isn't passed becauses3lacks an active sequence. -
s2: Check 1 isn't passed because the state ofs1is empty. it passes Check 2 because it meets the condition ofTs - s1.Ts < 5m. Record 4 and itsm_id(0) are added to the state and the output. このレコードの値は、s2.Tsと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 ofEvent == "Start".
State:
| ステップ | 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" |
各ステップで評価を記録します。
-
s3: Check 1 is passed becauses2is nonempty and it meets thes3condition ofEvent == "Stop". この一致により、s2の状態がクリアされ、s2のシーケンスがs3に昇格されます。 Record 5 and itsm_id(0) are added to the state and the output. -
s2: Check 1 isn't passed because the state ofs1is empty, and Check 2 isn't passed becauses2lacks 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 ofEvent == "Start".
State:
| ステップ | 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" |
各ステップで評価を記録します。
-
s3: Check 1 isn't passed because the state ofs2is empty, and Check 2 isn't passed becauses3doesn't meet thes3condition ofEvent == "Stop". -
s2: Check 1 isn't passed because the state ofs1is empty, and Check 2 isn't passed becauses2lacks 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 ofEvent == "Start". Record 6 is discarded without affecting the state or output.
State:
| ステップ | 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" |
各ステップで評価を記録します。
-
s3: Check 1 isn't passed because the state ofs2is empty, and Check 2 isn't passed because it doesn't meet the condition ofEvent == "Stop". -
s2: Check 1 isn't passed because the state ofs1is empty, and Check 2 isn't passed becauses2lacks an active sequence. -
s1: Check 1 isn't passed because there's no previous step. it passes Check 2 because it meets the condition ofEvent == "Start". この一致により、新しいs1でm_idで新しいシーケンスが開始されます。 Record 7 and itsm_id(1) are added to the state and the output.
State:
| ステップ | 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
現在、状態に 2 つのアクティブ なシーケンスがあります。
Record 8
| Ts | Event |
|---|---|
| 11m | "E" |
各ステップで評価を記録します。
-
s3: Check 1 isn't passed because the state ofs2is empty, and Check 2 isn't passed because it doesn't meet thes3condition ofEvent == "Stop". -
s2: Check 1 is passed because the state ofs1is nonempty and the record meets the condition ofTs - s1.Ts < 5m. この一致により、s1の状態がクリアされ、s1のシーケンスがs2に昇格されます。 Record 8 and itsm_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 ofEvent == "Start".
State:
| ステップ | 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" |
各ステップで評価を記録します。
-
s3: Check 1 is passed becauses2is nonempty and it meets thes3condition ofEvent == "Stop". この一致により、s2の状態がクリアされ、s2のシーケンスがs3に昇格されます。 Record 9 and itsm_id(1) are added to the state and the output. -
s2: Check 1 isn't passed because the state ofs1is empty, and Check 2 isn't passed becauses2lacks an active sequence. -
s1: Check 1 isn't passed because there's no previous step. it passes Check 2 because it meets the condition ofEvent == "Start". この一致により、新しいs1でm_idで新しいシーケンスが開始されます。
State:
| ステップ | 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 |