【问题标题】:RavenDB calculate averageRavenDB 计算平均值
【发布时间】:2013-02-21 22:58:55
【问题描述】:

使用 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 分组。

有没有更好的办法?

【问题讨论】:

  • 犹大,这完全坏了。您似乎想在单个文档上执行此操作,但是因为您的 reduce 为 Id 返回 null,所以它们会混合在一起。
  • 谢谢。我想我不明白在 reduce 中使用 null Id 的含义。

标签: ravendb average


【解决方案1】:

如果要将所有项目分组以获得单个结果,则只需按常数值分组,例如零。

虽然在客户端做这件事并没有什么问题,但在索引本身内部计算平均值通常很方便。只要总和是通过 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
                                };
    }
}

【讨论】:

  • 按零分组,以便将它们全部放入一个组中。回想起来,这听起来很明显。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-01-14
  • 2012-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多