時間枠の結合
適用対象: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
多くの場合、操作 ID やセッション ID などの高カーディナリティ キーで 2 つの大きなデータセット間を結合し、左側と右側の列の間に "時間距離" の制限を追加することで、左側 ($left) レコードと一致する必要がある右側 (datetime
$right) レコードをさらに制限すると便利です。
上記の操作は通常の結合操作とは異なります。左と右のデータセット間でカーディナリティの高いキーを照合する equi-join
部分の場合、システムは距離関数を適用してそれを使用して結合を大幅に高速化することもできます。
手記
距離関数は等値のように動作しません (つまり、dist(x,y) と dist(y,z) の両方が true の場合、その dist(x,z) も true に従いません)。 これは、"対角結合" と呼ばれることもあります。
時間枠のないイベント シーケンスを識別する例
この例では、比較的小さな時間枠内でイベント シーケンスを識別するために、次のスキーマを持つテーブル T
を使用します。
-
SessionId
: 関連付け ID を持つstring
型の列。 -
EventType
: レコードのイベントの種類を識別するstring
型の列。 -
Timestamp
:datetime
型の列は、レコードによって記述されたイベントがいつ発生するかを示します。
SessionId | EventType | タイムスタンプ |
---|---|---|
0 | ある | 2017-10-01T00:00:00Z |
0 | B | 2017-10-01T00:01:00Z |
1 | B | 2017-10-01T00:02:00Z |
1 | ある | 2017-10-01T00:03:00Z |
3 | ある | 2017-10-01T00:04:00Z |
3 | B | 2017-10-01T00:10:00Z |
次のクエリでは、データセットを作成し、イベントの種類 A
後にイベントの種類が 1min
時間枠内で B
されたすべてのセッション ID を識別します。
クエリ を実行する
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
| 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
出力
SessionId | 始める | 終わり |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
時間枠で最適化された例
このクエリを最適化するために、時間枠を考慮してクエリを書き直すことができます。 時間枠は結合キーとして表されます。
datetime
値が時間枠の半分のサイズのバケットに "分離" されるようにクエリを書き直します。
equi-join
を使用してバケット ID を比較します。
このクエリでは、同じセッション (SessionId) 内のイベントのペアが検索されます。ここで、"A" イベントの後に 1 分以内に "B" イベントが続きます。 セッション ID、'A' イベントの開始時刻、および 'B' イベントの終了時刻を投影します。
クエリ を実行する
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
出力
SessionId | 始める | 終わり |
---|---|---|
0 | 2017-10-01 00:00:00.0000000 | 2017-10-01 00:01:00.0000000 |
500 万件のデータ クエリ
次のクエリでは、5M レコードと約 1M セッション ID の広範なデータセットをエミュレートし、時間枠の手法を使用してクエリを実行します。
クエリ を実行する
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
出力
数える |
---|
3344 |
関連コンテンツ
- 結合演算子 を する