我正在使用 RavenDB 来存储一系列事件。这些事件有一个我用来按天分组的日期 (DateTime.Date)。我试图按小时添加一些统计数据,但我似乎无法找到一种干净的方法。
简单的方法:
public class DailyStats : AbstractIndexCreationTask<Incident, DateStat>
{
public DailyStats()
{
Map = docs => from doc in docs
select new
{
doc.OccuredOn,
Hour0 = doc.OccuredOn.Hour == 0 ? 1 : 0
Hour1 = doc.OccuredOn.Hour == 1 ? 1 : 0
//....
};
Reduce = mapped => from m in mapped
group m by new { m.Date.Date }
into g
select new
{
g.Key.Date,
Hour0 = g.Sum(x => x.Hour0),
Hour1 = g.Sum(x => x.Hour1)
//....
}
}
}
但这是可怕的重复。相反,我正在尝试使用字典:
public class DailyStats : AbstractIndexCreationTask<Incident, DateStat>
{
public DailyStats()
{
Map = docs => from doc in docs
select new
{
doc.OccuredOn,
IncidentsByHour = Enumerable.Range(0, 24).ToDictionary(h => h, h => doc.IncidentDate.Hour == h ? 1 : 0),
};
Reduce = mapped => from m in mapped
group m by new { m.Date.Date }
into g
select new
{
g.Key.Date,
IncidentsByHour = Enumerable.Range(0, 24).Select(h => g.Sum(x => x.IncidentsByHour[h])),
}
}
}
抛出异常:
我不确定如何解决此异常,因为它发生在 Raven 一侧。
按天分组的原因是我需要提取 365 天的统计数据,但仍然有一些按小时计算的基本信息。改为有两个索引会更好,一个按天,一个按小时(总共加载 365 + 24 条记录。我的理解是索引越大但越少越好)?
最佳答案
试试这个:
public class DailyStats : AbstractIndexCreationTask<Incident, DateStat>
{
public DailyStats()
{
Map = docs =>
from doc in docs
select new
{
Date = doc.OccuredOn,
IncidentsByHour = new Dictionary<int, int> { { doc.OccuredOn.Hour, 1 } }
};
Reduce = mapped =>
from m in mapped
group m by new { m.Date.Date }
into g
select new
{
Date = g.Key,
IncidentsByHour = g.SelectMany(x => x.IncidentsByHour)
.GroupBy(x => x.Key)
.OrderBy(x => x.Key)
.ToDictionary(x => x.Key, x => x.Sum(y => y.Value))
};
}
}
这里唯一的区别是,在没有发生事故的几个小时内,您不会在字典中找到任何项目。
Raven 确实仍然存在某种错误。 map 应该可以这样写:
IncidentsByHour = Enumerable.Range(0, 24)
.ToDictionary(h => h, h => doc.OccuredOn.Hour == h ? 1 : 0)
但是由于某种奇怪的原因它失败了。我会将其报告为错误。
是的,与许多小索引相比,拥有更少的大索引通常更好。
关于mapreduce - 使用 RavenDB 索引按小时计数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19759687/