使用 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 分组。
有更好的方法吗?
最佳答案
如果您要将所有项目分组为一个结果,则只需按常量值分组,例如零。
尽管在客户端执行此操作没有任何问题,但在索引本身内计算平均值通常很方便。只要求和是通过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
};
}
}
关于RavenDB计算平均值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14994996/