2013-02-21 215 views
2

用RavenDB計算簡單平均值的正確方法是什麼?RavenDB計算平均值

我的目標:

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

我的第一天真的想法是,「!我就用.SUM」,但我得到了一個運行時錯誤說烏鴉沒有做到這一點對性能方面的原因,這使得感。

接下來的想法是,「我會製作一個小地圖/減少索引來計算它!」所以,我想出了這個:

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。

有沒有更好的方法?

+0

猶大, 這是完全破碎。 您似乎想要在單個文檔上執行此操作,但由於您的縮減針對Id返回null,因此它們都會混合在一起。 – 2013-02-21 07:52:41

+0

謝謝。我想我不明白在減少中有一個空Id的含義。 – 2013-02-21 15:22:48

回答

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

按零分組,以便將它們全部放入一個組中。回想起來這聽起來很明顯。謝謝! – 2013-02-21 15:24:08