Большие поля MultiMap + Reduce or Denormalize Count - PullRequest
1 голос
/ 27 января 2012

Просто интересно ваше мнение о том, как я должен смоделировать свои документы для этого сценария.

На данный момент у меня есть то, что кажется сложным индексом MultiMap, который извлекает счетчики / статистику из нескольких других коллекций документов, на моем компьютере разработчика он возвращает небольшое подмножество тестовых данных менее чем за 80 мс (что меня устраивает) .

Какова будет производительность, когда это произойдет на моем производственном сервере, в среднем каждый микс будет получать около 500 просмотров в неделю, 200 загрузок в неделю и несколько лайков, избранных и комментариев. Я буду отображать 20-25 миксов на странице.

Вы бы сохранили этот дизайн, или было бы лучше денормализовать мои счетчики и сохранить их в аудио документе, если индекс будет работать намного меньше, если он будет работать нормально?

public class AudioWithCounters : AbstractMultiMapIndexCreationTask<AudioWithCounters.AudioViewModel>
    {
        public class AudioViewModel
        {
            public string Id { get; set; }
            public string ArtistName { get; set; }
            public string Name { get; set; }
            public int TotalComments { get; set; }
            public int TotalDownloads { get; set; }
            public int TotalPlays { get; set; }
            public int TotalLikes { get; set; }
            public int TotalFavourites { get; set; }
            public int WeeksComments { get; set; }
            public int WeeksDownloads { get; set; }
            public int WeeksPlays { get; set; }
            public int WeeksLikes { get; set; }
            public int WeeksFavourites { get; set; }
        }

        public AudioWithCounters()
        {
            AddMap<Audio>(audios => from audio in audios
                                    select new
                                    {
                                        Id = audio.Id,
                                        ArtistName = audio.ArtistName,
                                        Name = audio.Name,
                                        TotalDownloads = 0,
                                        TotalComments = audio.CommentsCount,
                                        TotalPlays = 0,
                                        TotalLikes = 0,
                                        TotalFavourites = 0,
                                        WeeksDownloads = 0,
                                        WeeksPlays = 0,
                                        WeeksComments = 0,
                                        WeeksLikes = 0,
                                        WeeksFavourites = 0
                                    });

            AddMap<AudioComments>(comments => from audioComment in comments
                                              from comment in audioComment.Comments
                                              where comment.CreatedAt >= DateTimeOffset.Now.AddDays(-7)
                                    select new
                                    {
                                        Id = audioComment.Audio.Id,
                                        ArtistName = (string)null,
                                        Name = (string)null,
                                        TotalDownloads = 0,
                                        TotalComments = 0,
                                        TotalPlays = 0,
                                        TotalLikes = 0,
                                        TotalFavourites = 0,
                                        WeeksDownloads = 0,
                                        WeeksPlays = 0,
                                        WeeksComments = 1,
                                        WeeksLikes = 0,
                                        WeeksFavourites = 0
                                    });


            AddMap<AudioCounter>(counters => from counter in counters
                                             where counter.Type == Core.Enums.Audio.AudioCounterType.Download
                                    select new
                                    {
                                        Id = counter.AudioId,
                                        ArtistName = (string)null,
                                        Name = (string)null,
                                        TotalDownloads = 1,
                                        TotalComments = 0,
                                        TotalPlays = 0,
                                        TotalLikes = 0,
                                        TotalFavourites = 0,
                                        WeeksDownloads = 0,
                                        WeeksPlays = 0,
                                        WeeksComments = 0,
                                        WeeksLikes = 0,
                                        WeeksFavourites = 0
                                    });

            AddMap<AudioCounter>(counters => from counter in counters
                                             where counter.Type == Core.Enums.Audio.AudioCounterType.Play
                                             select new
                                             {
                                                 Id = counter.AudioId,
                                                 ArtistName = (string)null,
                                                 Name = (string)null,
                                                 TotalDownloads = 0,
                                                 TotalPlays = 1,
                                                 TotalComments = 0,
                                                 TotalLikes = 0,
                                                 TotalFavourites = 0,
                                                 WeeksDownloads = 0,
                                                 WeeksPlays = 0,
                                                 WeeksComments = 0,
                                                 WeeksLikes = 0,
                                                 WeeksFavourites = 0
                                             });

            AddMap<AudioCounter>(counters => from counter in counters
                                             where counter.Type == Core.Enums.Audio.AudioCounterType.Download
                                             where counter.DateTime >= DateTimeOffset.Now.AddDays(-7)
                                             select new
                                             {
                                                 Id = counter.AudioId,
                                                 ArtistName = (string)null,
                                                 Name = (string)null,
                                                 TotalDownloads = 0,
                                                 TotalPlays = 0,
                                                 TotalComments = 0,
                                                 TotalLikes = 0,
                                                 TotalFavourites = 0,
                                                 WeeksDownloads = 1,
                                                 WeeksPlays = 0,
                                                 WeeksComments = 0,
                                                 WeeksLikes = 0,
                                                 WeeksFavourites = 0
                                             });

            AddMap<Like>(likes => from like in likes
                                             select new
                                             {
                                                 Id = like.AudioId,
                                                 ArtistName = (string)null,
                                                 Name = (string)null,
                                                 TotalDownloads = 0,
                                                 TotalPlays = 0,
                                                 TotalComments = 0,
                                                 TotalLikes = 1,
                                                 TotalFavourites = 0,
                                                 WeeksDownloads = 0,
                                                 WeeksPlays = 0,
                                                 WeeksComments = 0,
                                                 WeeksLikes = 0,
                                                 WeeksFavourites = 0
                                             });

            AddMap<Favourite>(favs => from fav in favs
                                  select new
                                  {
                                      Id = fav.AudioId,
                                      ArtistName = (string)null,
                                      Name = (string)null,
                                      TotalDownloads = 0,
                                      TotalPlays = 0,
                                      TotalComments = 0,
                                      TotalLikes = 0,
                                      TotalFavourites = 1,
                                      WeeksDownloads = 0,
                                      WeeksPlays = 0,
                                      WeeksComments = 0,
                                      WeeksLikes = 0,
                                      WeeksFavourites = 0
                                  });

            AddMap<AudioCounter>(counters => from counter in counters
                                             where counter.Type == Core.Enums.Audio.AudioCounterType.Play
                                             where counter.DateTime >= DateTimeOffset.Now.AddDays(-7)
                                             select new
                                             {
                                                 Id = counter.AudioId,
                                                 ArtistName = (string)null,
                                                 Name = (string)null,
                                                 TotalDownloads = 0,
                                                 TotalPlays = 0,
                                                 TotalComments = 0,
                                                 TotalLikes = 0,
                                                 TotalFavourites = 0,
                                                 WeeksDownloads = 1,
                                                 WeeksPlays = 0,
                                                 WeeksComments = 0,
                                                 WeeksLikes = 0,
                                                 WeeksFavourites = 0
                                             });

            AddMap<Like>(likes => from like in likes
                                  where like.DateCreated >= DateTimeOffset.Now.AddDays(-7)
                                  select new
                                  {
                                      Id = like.AudioId,
                                      ArtistName = (string)null,
                                      Name = (string)null,
                                      TotalDownloads = 0,
                                      TotalPlays = 0,
                                      TotalComments = 0,
                                      TotalLikes = 0,
                                      TotalFavourites = 0,
                                      WeeksDownloads = 0,
                                      WeeksPlays = 0,
                                      WeeksComments = 0,
                                      WeeksLikes = 1,
                                      WeeksFavourites = 0
                                  });

            AddMap<Favourite>(favs => from fav in favs
                                      where fav.DateCreated >= DateTimeOffset.Now.AddDays(-7)
                                      select new
                                      {
                                          Id = fav.AudioId,
                                          ArtistName = (string)null,
                                          Name = (string)null,
                                          TotalDownloads = 0,
                                          TotalPlays = 0,
                                          TotalComments = 0,
                                          TotalLikes = 0,
                                          TotalFavourites = 0,
                                          WeeksDownloads = 0,
                                          WeeksPlays = 0,
                                          WeeksComments = 0,
                                          WeeksLikes = 0,
                                          WeeksFavourites = 1
                                      });

            Reduce = results => from result in results
                                group result by result.Id
                                    into g
                                    select new
                                    {
                                        Id = g.Key,
                                        ArtistName = g.Select(x => x.ArtistName).Where(x => x != null).FirstOrDefault(),
                                        Name = g.Select(x => x.Name).Where(x => x != null).FirstOrDefault(),
                                        TotalDownloads = g.Sum(x => x.TotalDownloads),
                                        TotalPlays = g.Sum(x => x.TotalPlays),
                                        TotalComments = g.Sum(x => x.TotalComments),
                                        TotalLikes = g.Sum(x => x.TotalLikes),
                                        TotalFavourites = g.Sum(x => x.TotalFavourites),
                                        WeeksComments = g.Sum(x => x.WeeksComments),
                                        WeeksDownloads = g.Sum(x => x.WeeksDownloads),
                                        WeeksPlays = g.Sum(x => x.WeeksPlays),
                                        WeeksLikes = g.Sum(x => x.WeeksLikes),
                                        WeeksFavourites = g.Sum(x => x.WeeksFavourites)
                                    };
        }

1 Ответ

2 голосов
/ 27 января 2012

Ваша модель хороша, придерживайтесь ее. Вы не заметите никаких проблем с производительностью во время запроса, потому что запросы будут выполняться к предварительно вычисленному индексу. Таким образом, вся работа выполняется асинхронно в фоновом потоке на сервере, что делает ваши запросы быстрыми.

Кроме того, вам не нужно беспокоиться о производительности при выполнении индекса, поскольку функции Map будут выполняться только для новых или измененных документов, а функция Reduce выполняется в группах, таким образом, только вычисляя новые результаты карты.

Предполагая, что это веб-сайт, о котором мы говорим, ваше альтернативное предложение денормализовать счетчик в аудиодокументах поставит вас перед проблемой, потому что тогда вам придется загружать и обновлять аудиодокумент каждый раз, когда кто-то нажимает на загрузку. или играть. Конечно, вы не заметите этого на небольшом сайте, но если у вас есть несколько одновременных посетителей, это станет проблемой. Кроме того, гораздо проще масштабировать, используя подход Map / Reduce и документы AudioCounter, потому что тогда вам нужно меньше беспокоиться о параллелизме и репликации - вместо этого, когда кто-то загружает или воспроизводит заголовок, просто вставьте новый документ AudioCounter. и продолжай.

Одна вещь, о которой вы должны знать, это счетчики недель. Если мои предположения о том, для чего они предназначены, верны, то они не сработают так, как у вас сейчас. Проблема в том, что у вас не может быть «агрегации диапазона» (не знаю правильного слова) внутри индекса карты / уменьшения - это всегда связано с итогами. Для этого вы можете создать фасетный запрос, который подсчитывает количество записей, или вместо этого использовать пакет репликации индекса, чтобы заполнить таблицу SQL, для которой вы можете выполнять специальные запросы. Извините, я не могу найти хороший пример для фасетного подхода сейчас, может быть, я соберу один на выходных ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...