0

我提出这个问题是因为它与 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();
        }
    }
4

0 回答 0