3

次のようなドキュメントがあります。

 order : 1
     event : { timestamp: 1/1/2012, employeeName: "mick" },
     event : { timestamp: 1/1/2012, employeeName: "mick" },
     event : { timestamp: 1/2/2012, employeeName: "rick" },
     event : { timestamp: 1/3/2012, employeeName: "mick" }

  order : 2
     event : { timestamp: 1/2/2012, employeeName: "mick" },
     event : { timestamp: 1/2/2012, employeeName: "rick" }

map-reduce クエリを実行して、日付ごとにグループ化された結果のリストと、注文ごとの従業員イベントの数を返したいと考えています。

この場合、Mick は 1/1 に 1 つの注文で 2 つのイベントを持っていました。他のすべての日は、11 月 2 日と 3 日に、注文ごとに従業員による 1 つのイベントがありました。だから私は次のような結果を持つMAP関数が必要です:

{ orderId: 1, date: 1/1/2012, employee: "mick", orderEventsCount: 2 },
{ orderId: 1, date: 1/2/2012, employee: "rick", orderEventsCount: 1 },
{ orderId: 2, date: 1/2/2012, employee: "mick", orderEventsCount: 1 },
{ orderId: 2, date: 1/2/2012, employee: "rick", orderEventsCount: 1 },
{ orderId: 1, date: 1/3/2012, employee: "mick", orderEventsCount: 1 }

次に、これらの結果を取得し、日付のみでグループ化し、1 つの注文で複数のイベントを持つ従業員の 1 日あたりの数を返す REDUCE 関数が必要です。

{ date: 1/1/2012, multipleEventsPerOrdercount: 1 },
{ date: 1/2/2012, multipleEventsPerOrdercount: 0 },
{ date: 1/3/2012, multipleEventsPerOrdercount: 0 }

Mick は、1 つの注文で 1 つの日付に複数のイベントが発生した唯一の従業員であるため、結果は、1 つの日付の注文で複数のイベントが発生した 1 人の従業員の数のみを返しました。

.NET で LINQ を使用して、この map-reduce Raven クエリを記述する最良の方法は何でしょうか?

ありがとう

4

1 に答える 1

1

クラスが次のようになっていると仮定します。

public class Order
{
  public string Id  { get; set; }
  public List<Event> Events { get; set; }
}

public class Event
{
  public DateTime Timestamp { get; set; }
  public string EmployeeName { get; set; }
}

次に、求めているインデックスは次のようになります。

public class Orders_EventCountsByDate : 
    AbstractIndexCreationTask<Order, Orders_EventCountsByDate.Result>
{
  public class Result
  {
    public DateTime Date { get; set; }
    public double Count { get; set; }
  }

  public Orders_EventCountsByDate()
  {
    Map = orders => from order in orders
                    from evt in order.Events
                    let subtotal = order.Events.Count(x => x.EmployeeName == evt.EmployeeName && x.Timestamp == evt.Timestamp)
                    select new
                    {
                      evt.Timestamp.Date,
                      Count = subtotal > 1 ? (1.0 / subtotal) : 0
                    };

    Reduce = results => from result in results
                        group result by result.Date
                        into g
                        select new
                        {
                          Date = g.Key,
                          Count = g.Sum(x => x.Count)
                        };
  }
}

そして、次のように使用します。

var counts = session.Query<Orders_EventCountsByDate.Result,
                           Orders_EventCountsByDate>();

ここでのコツは、各イベントがカウントにどれだけ寄与するかをマップで決定していることです。イベントが 1 つしかない場合は、0 を寄付します。複数のイベントがある場合、各イベントは合計の一部を占めます。これらの分数は後で reduce で合計され、ほぼ整数に戻ります。倍精度浮動小数点演算は整数に戻す必要がありますが、安全のために、クライアント側のコードで最も近い整数に丸めることをお勧めします。

これは、すべてのイベントが同じタイムゾーンにあり、夏時間の変更を気にしない、または時刻が UTC であることも前提としています。どちらでもない場合は、DateTimeOffset を使用する必要があり、各従業員の日の概念を決定する際には、さらに考慮すべきことがあります。

于 2012-11-09T15:22:21.030 に答える