2012-01-27 4 views
1

이 시나리오에서 내 문서를 어떻게 모델화해야하는지에 대한 귀하의 의견을 궁금하게 생각하십시오.큰 MultiMap + 숫자 줄이거 나 역 정규화

현재로서는 여러 다른 문서 모음에서 카운터/통계를 가져 오는 복잡한 MultiMap 색인이있는 것 같습니다. 내 dev 컴퓨터에서는 80ms 미만의 작은 크기의 테스트 데이터를 반환합니다 (이는 만족합니다.)).

내 프로덕션 서버로 갈 때의 성능은 평균적으로 매주 평균 약 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) 
            }; 
     } 

답변

2

모델이 좋다. 조회가 사전 계산 된 색인에 대해 실행되므로 조회시 성능. 제를 알지 못합니다. 따라서 모든 작업은 서버의 백그라운드 스레드에서 비동기 적으로 수행되므로 쿼리가 빨라집니다.

지도 기능은 새 문서 나 변경된 문서에서만 실행되고 줄이기 기능은 그룹으로 실행되므로 새 맵 결과 만 계산하므로 인덱스 실행의 성능에 대해 걱정할 필요가 없습니다.

우리가 말하고있는 웹 사이트라고 가정하면, 오디오 문서에 셀 수를 비정규 화하는 대체 방법은 누군가가 클릭 할 때마다 오디오 문서를로드하고 업데이트해야하기 때문에 다운로드 또는 재생. 당연히 당신은 작은 위치에 그것을주의하지 않을 것입니다, 그러나 당신은 일부 동시 방문자가 있으면 이것은 문제가 될 것입니다. 또한 Map/Reduce 방식과 AudioCounter 문서를 사용하여 확장 성을 향상시키는 것이 훨씬 쉽습니다. 그 이유는 동시성과 복제에 대해 걱정할 필요가 없기 때문입니다. 대신 누군가가 타이틀을 다운로드하거나 재생할 때 새로운 AudioCounter 문서 그리고 계속해라.

주의해야 할 점 중 하나는 주 카운터입니다. 그들이 의도 한 것에 대한 나의 가정이 사실이라면, 당신이 지금 가지고있는 방식대로 작동하지 않을 것입니다. 문제는지도/감축 지표 내에서 "범위 집계"(정확한 단어를 알 수 없음)를 가질 수 없다는 것입니다. 이는 항상 합계에 관한 것입니다. 이렇게하려면 레코드 수를 세는 패싯 쿼리를 만들거나 대신 인덱스 복제 번들을 사용하여 임시 쿼리를 수행 할 수있는 SQL 테이블을 채 웁니다. 죄송합니다. 지금 당장 패싯 접근법에 대한 좋은 예를 찾지 못했을 것입니다. 어쩌면 주말에 하나를 정리할 것입니다 ...

+0

대단히 감사합니다. Daniel. 패싯 접근 방식을 쓰기를 기대해보십시오 ... 그러나 주 카운터는 현재지도/축소 지수에서 제대로 작동하고 있습니다. 그러나 나는 귀하의 조언을 구할 것입니다. –

관련 문제