2013-02-21 1 views
2

Каков правильный способ вычисления простого среднего значения с помощью RavenDB?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.

Есть ли лучший способ?

+0

Judah, Это совершенно сломан. Кажется, что вы хотите сделать это на одном документе, но поскольку ваше сокращение возвращает null для Id, все это будет смешиваться. –

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

Группа на ноль, чтобы все они попали в одну группу. Это выглядит ретроспективно. Благодаря! –