上篇博文介绍了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基础查询操作中的用户自定义聚合部分。

作者: StreamInsight 发表于 2011-08-21 23:42 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"