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

これは機能すると思いますが、グループ化するものが実際には何もないため、ハックのように感じます。そのため、曲 ID でグループ化しました。

もっと良い方法はありますか?

4

1 に答える 1

3

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