你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
时间窗口联接
适用于:✅Microsoft Fabric✅Azure 数据资源管理器✅Azure Monitor✅Microsoft Sentinel
在一些高基数键(如作 ID 或会话 ID)的两个大型数据集之间联接,并进一步限制需要与左侧($left)记录匹配的每个左侧($left)记录的右侧($right)记录,从而限制左侧和右侧 datetime
列之间的“时间距离”。
上述作不同于通常的联接作,因为对于匹配左右数据集之间的高基数键的 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 |
使用时间窗口优化的示例
若要优化此查询,可以重写它以考虑时间范围。 THe 时间范围表示为联接键。 重写查询,以便将 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 万数据查询
下一个查询模拟 500 万条记录和大约 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 |