2

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

我的对象:

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

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

下一个想法是,“我会做一个计算它的小 map/reduce 索引!” 所以我想出了这个:

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;
                    }

我认为这很有效,但感觉很hackish,因为真的没有什么可分组的,所以我只是按歌曲ID分组。

有没有更好的方法?

4

1 回答 1

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
                                };
    }
}
于 2013-02-21T14:58:55.893 回答