【问题标题】:Large MultiMap+Reduce or Denormalize Count fields大型 MultiMap+Reduce 或 Denormalize Count 字段
【发布时间】:2012-02-20 04:19:44
【问题描述】:

只是想知道您对我应该如何为这种情况的文档建模的意见。

目前我有一个看起来很复杂的 MultiMap 索引,它从其他几个文档集合中提取计数器/统计信息,在我的开发机器上,它在 80 毫秒内返回一小部分测试数据(我很满意) .

当它在我的生产服务器上运行时,性能会如何,平均每个混音每周会收到大约 500 次播放、每周 200 次下载和一些点赞、收藏和 cmets。我将在每页显示 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)
                                    };
        }

【问题讨论】:

    标签: ravendb denormalization multimap


    【解决方案1】:

    你的模型很好,坚持下去。您不会在查询时注意到任何性能问题,因为查询将针对预先计算的索引运行。所以所有工作都是在服务器上的后台线程中异步完成的——这使您的查询速度更快。

    此外,您不必担心索引执行的性能,因为 Map 函数只会在新的或更改的文档上运行,而 Reduce 函数是分组执行的,因此只计算新的 map 结果。

    假设这是一个我们正在谈论的网站,您将非规范化计数到音频文档中的替代建议会给您带来麻烦,因为这样您就需要在每次有人点击下载时加载和更新音频文档或玩。当然,在小型网站上您不会注意到这一点,但如果您有 一些 个同时访问者,这将成为一个问题。此外,使用 Map/Reduce 方法和 AudioCounter 文档进行扩展要容易得多,因为这样您就不必担心并发和复制 - 相反,当有人下载​​或播放标题时,只需放入一个新的 AudioCounter 文档继续。

    不过,您应该注意的一件事是周计数器。如果我对它们的用途的假设是正确的,那么它们将不会像你现在拥有的那样工作。问题是,在 map/reduce 索引中不能有“范围聚合”(不知道正确的词)——它总是关于总数。为此,您可以提出一个计算记录数的构面查询,或者使用索引复制包来填充一个 SQL 表,您可以在该表上执行即席查询。很抱歉,我现在没有找到一个好的切面方法的例子,也许我会在周末整理一个......

    【讨论】:

    • 出色的回答再次感谢丹尼尔。期待 Facet 方法写出来……但是周计数器“似乎”目前在 map/reduce 索引中运行良好,但我会接受你的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-09
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    相关资源
    最近更新 更多