私は 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();
}
}