Ravendb mapreduce группировка по нескольким полям - PullRequest
6 голосов
/ 23 марта 2011

У нас есть сайт с потоковым видео, и мы хотим отобразить три отчета о самых просматриваемых видео за последнюю неделю, месяц и год (скользящее окно).

Мы сохраняем документ в ravendb при каждом просмотре видео:

public class ViewedContent
{
    public string Id { get; set; }
    public int ProductId { get; set; }
    public DateTime DateViewed { get; set; }
}

У нас возникают проблемы с выяснением того, как определить индексы / сокращения, которые лучше всего поддерживали бы создание этих трех отчетов.

Мы попробовали следующую карту / уменьшить.

public class ViewedContentResult
{
    public int ProductId { get; set; }
    public DateTime DateViewed { get; set; }
    public int Count { get; set; }
}

public class ViewedContentIndex :
        AbstractIndexCreationTask<ViewedContent, ViewedContentResult>
{
    public ViewedContentIndex()
    {
        Map = docs => from doc in docs
                      select new
                                 {
                                     doc.ProductId,
                                     DateViewed = doc.DateViewed.Date,
                                     Count = 1
                                 };

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

Но этот запрос выдает ошибку:

var lastSevenDays = session.Query<ViewedContent, ViewedContentIndex>()
                .Where( x => x.DateViewed > DateTime.UtcNow.Date.AddDays(-7) );

Ошибка: «DateViewed не проиндексирован»

В конечном итоге мы хотим запросить что-то вроде:

var lastSevenDays = session.Query<ViewedContent, ViewedContentIndex>()
                .Where( x => x.DateViewed > DateTime.UtcNow.Date.AddDays(-7) )
                .GroupBy( x => x.ProductId )
                .OrderBy( x => x.Count )

Это на самом деле не компилируется, потому что OrderBy не так; Count не является допустимым свойством здесь.

Любая помощь здесь будет оценена.

1 Ответ

10 голосов
/ 24 марта 2011

Каждый отчет - это отдельная GROUP BY, если вы находитесь в среде SQL, которая говорит вам, что вам нужно три индекса - один с только месяцем, один с записями по неделям, один по месяцам и один по годам (или, возможно, немного отличается в зависимости от того, как вы собираетесь выполнить запрос.

Теперь у вас есть DateTime, что представляет некоторые проблемы, и вы на самом деле хотите сделать это индексирование компонента Year для DateTime, компонента Month для даты и времени и компонента Day для этой даты. время. (Или один или два из них в зависимости от того, какой отчет вы хотите сгенерировать.

Я только парацитирую ваш код здесь, так что, очевидно, он не будет компилироваться, но:

public class ViewedContentIndex :
    AbstractIndexCreationTask<ViewedContent, ViewedContentResult>
{
public ViewedContentIndex()
{
    Map = docs => from doc in docs
                  select new
                             {
                                 doc.ProductId,
                                 Day = doc.DateViewed.Day,
                                 Month = doc.DateViewed.Month,
                                 Year = doc.DateViewed.Year
                                 Count = 1
                             };

    Reduce = results => from result in results
                        group result by new {
                             doc.ProductId,
                             doc.DateViewed.Day,
                             doc.DateViewed.Month,
                             doc.DateViewed.Year
                        }
                        into agg
                        select new
                                   {
                                       ProductId = agg.Key.ProductId,
                                       Day = agg.Key.Day,
                                       Month = agg.Key.Month,
                                       Year = agg.Key.Year  
                                       Count = agg.Sum(x => x.Count)
                                   };
}

}

Надеюсь, вы увидите, чего я пытаюсь достичь этим - вы хотите, чтобы ВСЕ компоненты в вашей группе были такими, какими они делают вашу группу уникальной.

Я не могу вспомнить, позволяет ли RavenDB вам делать это с DateTimes, и у меня его нет на этом компьютере, поэтому я не могу это проверить, но теория остается прежней.

Итак, повторить

Вы хотите индекс для вашего отчета по неделям + идентификатор продукта Вы хотите индекс для вашего отчета по месяцам + идентификатор продукта Вы хотите индекс для вашего отчета по году + идентификатор продукта

Надеюсь, это поможет, извините, я не могу дать вам скомпилированный пример, отсутствие вороны делает его немного сложным: -)

...