【原创】StreamInsight查询系列(四)——基本查询操作之聚合
上篇博文介绍了StreamInsight基础查询操作中的过滤部分。这篇文章将主要介绍StreamInsight基础查询操作中的聚合部分。
测试数据准备
为了方便测试查询,我们首先准备一个静态的测试数据源:
var weatherData = new[] { new { Timestamp = new DateTime(2010, 1, 1, 0, 00, 00, DateTimeKind.Utc), Temperature = -9.0, StationCode = 71395, WindSpeed = 4}, new { Timestamp = new DateTime(2010, 1, 1, 0, 30, 00, DateTimeKind.Utc), Temperature = -4.5, StationCode = 71801, WindSpeed = 41}, new { Timestamp = new DateTime(2010, 1, 1, 1, 00, 00, DateTimeKind.Utc), Temperature = -8.8, StationCode = 71395, WindSpeed = 6}, new { Timestamp = new DateTime(2010, 1, 1, 1, 30, 00, DateTimeKind.Utc), Temperature = -4.4, StationCode = 71801, WindSpeed = 39}, new { Timestamp = new DateTime(2010, 1, 1, 2, 00, 00, DateTimeKind.Utc), Temperature = -9.7, StationCode = 71395, WindSpeed = 9}, new { Timestamp = new DateTime(2010, 1, 1, 2, 30, 00, DateTimeKind.Utc), Temperature = -4.6, StationCode = 71801, WindSpeed = 59}, new { Timestamp = new DateTime(2010, 1, 1, 3, 00, 00, DateTimeKind.Utc), Temperature = -9.6, StationCode = 71395, WindSpeed = 9}, };
weatherData代表了一系列的天气信息(时间戳、温度、气象站编码以及风速)。
接下去将weatherData转变为点类型复杂事件流:
var weatherStream = weatherData.ToPointStream(Application, t => PointEvent.CreateInsert(t.Timestamp, t), AdvanceTimeSettings.IncreasingStartTime);
基础聚合
问题1:怎样每隔3小时计算一次所有事件的平均值(平均温度和平均风速)?
var averageQuery = from win in weatherStream.TumblingWindow( TimeSpan.FromHours(3), HoppingWindowOutputPolicy.ClipToWindowEnd) select new { AverageTemperature = win.Avg(e => e.Temperature), AverageWindspeed = win.Avg(e => e.WindSpeed) };使用下面的语句将结果输出到LINQPad结果窗口:
(from p in averageQuery.ToPointEnumerable() where p.EventKind == EventKind.Insert select p).Dump();
最终的结果包含以下两个事件:
结果中的第一个事件为时间段[2010/1/1 0:00:00, 2010/1/1 3:00:00) 的平均值结果(注意StreamInsight中的时间段都是先闭后开的),即前6个事件的平均值结果:如平均温度AverageTemperature = – (9.0 + 4.5 + 8.8 + 4.4 + 9.7 + 4.6) / 6 = -6.83333333,平均风速AverageWindspeed = (4 + 41 + 6 + 39 + 9 + 59) / 6 = 26.3333333。
结果中的第二个事件为时间段[2010/1/1 3:00:00, 2010/1/1 6:00:00)的平均值结果。由于输入数据仅有最后一个事件在这个范围内,因此平均温度AverageTemperature和平均风速AverageWindspeed均为该事件对应的温度值和风速值。
问题2:怎样每隔1小时的计算过去3小时内所有事件的平均值?
var averageQuery2 = from win in weatherStream.HoppingWindow( TimeSpan.FromHours(3), TimeSpan.FromHours(1), HoppingWindowOutputPolicy.ClipToWindowEnd) select new { AverageTemperature = win.Avg(e => e.Temperature), AverageWindspeed = win.Avg(e => e.WindSpeed) };
与问题1查询不同之处在于,这里使用了HoppingWindow来实现每隔1小时计算过去3小时的语义动作。同样将结果导出如下:
这里要注意的是,按理说应当从2010/1/1 0:00:00开始计算每隔1小时过去3小时的事件平均值,但是在往前的时间段里,有两个事件分别被覆盖在了[2009/12/31 22:00:00, 2010/1/1 1:00:00)和[2009/12/31 23:00:00, 2010/1/1 2:00:00)的时间段内,因此输出包含了这两个事件。
问题3:怎样计算每当一个新事件到达时,过去1小时内的平均值?
var averageQuery3 = from win in weatherStream .AlterEventDuration(e => TimeSpan.FromHours(1)) .SnapshotWindow(SnapshotWindowOutputPolicy.Clip) select new { AverageTemperature = win.Avg(e => e.Temperature), AverageWindspeed = win.Avg(e => e.WindSpeed), EventCount = win.Count() };
使用SnapshotWindow可以达到每当一个新事件到达时输出事件的效果,配合AlterEventDuration将每个点事件向后延伸为持续时间1小时的间隔事件,可以计算出多个事件的平均值。
输出结果如下:
问题4:怎样计算1个小时内的事件数目?
类似问题1,只不过这里要使用的聚合函数不再是Avg,而是Count。
var countQuery = from win in weatherStream.TumblingWindow( TimeSpan.FromHours(1), HoppingWindowOutputPolicy.ClipToWindowEnd) select new { EventCount = win.Count() };
结果如下:
下一篇将介绍StreamInsight基础查询操作中的用户自定义聚合部分。