RavenDB计算平均值

时间:2013-02-21 05:11:19

标签: ravendb average

使用RavenDB计算简单平均值的正确方法是什么?

我的对象:

class Song 
{
    public int CommunityRank { get; set; }
}

我的第一个天真的想法是,“我只会使用.Sum!”,但我收到一个运行时错误,说Raven因性能原因不这样做,这是有道理的。

接下来的想法是,“我会制作一个小地图/缩小指数来计算它!”所以我想出了这个:

public Songs_CommunityRankIndex()
{
    Map = songs => from song in songs
                   select new 
                   { 
                       Id = song.Id, // # Hack? I only use this for grouping in the reduce.
                       SongCount = 1, 
                       RankSum = song.CommunityRank
                   };

   Reduce = results => from result in results
                       group result by result.Id into g
                       select new
                       {
                           Id = default(string),
                           SongCount = g.Sum(s => s.SongCount),
                           RankSum = g.Sum(s => s.RankSum)
                       };
}


...
// Now to calculate the average:
var communityRankStats = session
                        .Query<Song, Songs_CommunityRankIndex>()
                        .As<Songs_CommunityRankIndex.Results>()
                        .FirstOrDefault();
                    if (communityRankStats != null)
                    {
                        var averageSongRank = (double)communityRankStats.RankSum / communityRankStats.SongCount;
                    }

我觉得这很有效,但感觉很乱,因为实际上没有什么可以分组的,所以我只是按照歌曲ID分组。

有更好的方法吗?

1 个答案:

答案 0 :(得分:3)

如果要为单个结果对所有项目进行分组,则只需按常量值进行分组,例如零。

虽然在客户端进行操作没有任何问题,但通常可以方便地计算索引本身内部的平均值。只要总和是通过map / reduce完成的,那么如果划分客户端或服务器端并不重要。

public class Songs_CommunityRankIndex : AbstractIndexCreationTask<Song, Songs_CommunityRankIndex.Results>
{
    public class Results
    {
        public long SongCount { get; set; }
        public long RankSum { get; set; }
        public double RankAverage { get; set; }
    }

    public Songs_CommunityRankIndex()
    {
        Map = songs => from song in songs
                        select new
                            {
                                SongCount = 1,
                                RankSum = song.CommunityRank,
                                RankAverage = 0
                            };

        Reduce = results => from result in results
                            group result by 0
                            into g
                            let songCount = g.Sum(s => s.SongCount)
                            let rankSum = g.Sum(s => s.RankSum)
                            select new
                                {
                                    SongCount = songCount,
                                    RankSum = rankSum,
                                    RankAverage = rankSum / songCount
                                };
    }
}