我提出这个问题是因为它与 C# 解决方案有关,但是,我在 RoR 解决方案中面临同样的困境,只是选择充分利用 Map-Reduce,放弃了抽象数据存储的所有希望。
MongoDB Map-Reduce 似乎是执行数据透视以及其他报告查询的方式。另一种选择是典型的文档存储库方式,例如典型的 EntityFramework (EF) 人员所鼓励的,是将逻辑移动到应用程序层。
在不深入讨论每种方法的相对优势的情况下,数据存储中的数据量被证明太大而无法将其全部提取到应用程序层。
下面的代码是一个概念验证 (POC),它产生了结果,但引出了我在这里提出的问题,有没有办法减少在 C#(任何 .NET)解决方案中使用 Map-Reduce 的影响?
贯穿始终的数据模型:
public class Call
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public Agent Agent { get; set; }
public Caller Caller { get; set; }
}
public class Agent : Person
{
public DateTime JoinedCompany { get; set; }
}
public class Caller : Person
{
}
Map-Reduce POC 中使用的数据模型:
public class AgentCallSummary
{
public ObjectId _id;
public AgentCallAggregateValues value;
public class AgentCallAggregateValues
{
public int count;
public int totalTimeOnCall;
}
}
下面的代码依赖于 CreateCollection() 和一个扩展方法 Dump(this T, string) ,它们被用来抽象地表示可以从任何文档存储中获取文档集合,并且可以转储任何文档(就像 LINQPad 提供的那样):
private void DemostrateMapReduce()
{
var calls = CreateCollectionCall<Call>();
calls.Count().Dump("Call Count");
const string mapJavascript =
@"function(){
var call = this;
/* averageCallTime should be fetched, simplified here, averageCallTime is used as the timeOnCall for calls that are in progress */
var averageCallTime = 15.0;
var calculateTotalTimeOnCall = function(startTime, endTime) {
if ((!endTime) || (!startTime)) {
return averageCallTime;
}
var diffMs = endTime - startTime;
return (diffMs / 1000) * 60;
};
emit(call.Agent._id, { count: 1, totalTimeOnCall: 1 });
}";
const string reduceJavascript =
@"function(key, values) {
var result = { count: 0, totalTimeOnCall: 0 };
values.forEach(function(value) {
result.count += value.count;
result.totalTimeOnCall += value.totalTimeOnCall;
});
return result;
}";
var mapReduceResult = calls.MapReduce(mapJavascript, reduceJavascript, MapReduceOptions.SetOutput(MapReduceOutput.Inline));
foreach (var item in mapReduceResult.GetInlineResultsAs<AgentCallSummary>())
{
item.Dump();
}
}