2012-11-27 61 views
4

我將每個用戶顯示有關事件的所有活動的用戶訂閱和進料將在最新的20個左右的活動拉開活動供稿。我擁有它的方式是所有活動,而不管其相關的事件是否存儲在一個集合中,並且文檔本身具有查詢和索引的「事件」屬性。基本查詢只是從集合中選擇活動,其中事件位於按日期排序的用戶事件訂閱列表中。我存儲了用戶事件訂閱列表的哈希值,並使用哈希值作爲xx秒的鍵值來緩存查詢結果,因此如果另一個用戶訂閱了相同的確切事件,我可以將結果從緩存中取出,而不是不關心結果是xx秒陳舊。最佳方式來處理基於活動的飼料在asp.net和ravendb

編輯:添加模型和查詢例如

型號:

User 
{ 
    // useless properties excluded 
    // fixed: hashset not list, can be quite large 
    HashSet<string> Subscriptions { get; set; } 
    string SubscriptionHash { get; set; } // precomputed hash of all strings in subscriptions 
} 

Activity 
{ 
    // Useless properties excluded 
    string ActivityType { get; set; } 
} 

查詢:

if (cache[user.SubscriptionHash] != null) 
    results = (HashSet<Activity>)cache[user.SubscriptionHash]; 
else 
    results = session.Query<Activity>().Where(user.Subscriptions.Contains(e => e.ActivityType)).Take(20).ToList(); 

// add results to cache 

我擔心的是,如果這是處理這個最好的辦法,或者有更好的ravendb巫毒使用。單集可能增長到數以百萬計,如果有很多的活動,我可能被存儲數千鍵在緩存中時,有數以千計的訂閱列表無窮的組合的用戶。這些供稿在用戶的着陸頁上,因此它被擊中了很多,我不想只是拋出更多的硬件來解決問題。

所以回答我真的想找或者是如果這是用最好的查詢,如果有更好的方法來做到這一點的烏鴉,當我可以查詢反對數百萬使用list.Contains文件。

這是一個使用ravendb的asp.net 4.5 mvc 4項目。

+0

您可以編輯並提供您目前建模的示例嗎? –

+0

可能是更好的表述爲。凡(E => e.ActivityType.In(user.Subscriptions.ToArray())) –

回答

1

現在,我將如何處理它。這是基於RaccoonBlog PostComments

我將存儲每個用戶在一個單獨的文檔與具有多個事件和最後的時間戳一起附加的屬性鏈接到它的用戶事件(即UserEvent在下面的示例)與用戶關聯的事件。這將保持用戶文檔小得多,但有很多重要的信息

在UserEvent中,它將是一個簡單的文檔持有ID,鏈接到用戶ID本文檔引用,「事件」集合和lasteventid。通過這種方式,每個「事件」如果需要就成爲維護的子文檔。

最後上UserEvent一個指數,可以讓你查詢數據容易

public class User 
{ 
    public string Id { get; set; } 
    // other user properties 

    public string UserEventId { get; set; } 
    public int NumberOfEvents { get; set; } 
    public DateTimeOffset LastEvent { get; set; } 
} 

public class UserEvent 
{ 
    public string Id { get; set; } 

    public string UserId { get; set; } 

    public int LastEventId { get; set; } 

    public ICollection<Event> Events { get; protected set; } 

    public int GenerateEventId() 
    { 
     return ++LastEventId; 
    } 

    public class Event 
    { 
     public int Id { get; set; } 
     public DateTimeOffset CreatedAt { get; set; } 
     public string ActivityType { get; set; } 
     // other event properties 
    } 
} 

public class UserEvents_CreationDate : AbstractIndexCreationTask<UserEvent, UserEvents_CreationDate.ReduceResult> 
{ 
    public UserEvents_CreationDate() 
    { 
     Map = userEvents => from userEvent in userEvents 
          from evt in userEvent.Events 
          select new 
          { 
           evt.CreatedAt, 
           EventId = evt.Id, 
           UserEventId = userEvent.Id, 
           userEvent.UserId, 
           evt.ActivityType 
          }; 
     Store(x => x.CreatedAt, FieldStorage.Yes); 
     Store(x => x.EventId, FieldStorage.Yes); 
     Store(x => x.UserEventId, FieldStorage.Yes); 
     Store(x => x.UserId, FieldStorage.Yes); 
     Store(x => x.ActivityType, FieldStorage.Yes); 
    } 

    public class ReduceResult 
    { 
     public DateTimeOffset CreatedAt { get; set; } 
     public int EventId { get; set; } 
     public string UserEventId { get; set; } 
     public string UserId { get; set; } 
     public string ActivityType { get; set; } 
    } 
} 

public static class Helpers 
{ 
    public static DateTimeOffset AsMinutes(this DateTimeOffset self) 
    { 
     return new DateTimeOffset(self.Year, self.Month, self.Day, self.Hour, self.Minute, 0, 0, self.Offset); 
    } 

    public static IList<Tuple<UserEvents_CreationDate.ReduceResult, User>> QueryForRecentEvents(
     this IDocumentSession documentSession, 
     Func 
      <IRavenQueryable<UserEvents_CreationDate.ReduceResult>, IQueryable<UserEvents_CreationDate.ReduceResult> 
      > processQuery) 
    { 
     IRavenQueryable<UserEvents_CreationDate.ReduceResult> query = documentSession 
      .Query<UserEvents_CreationDate.ReduceResult, UserEvents_CreationDate>() 
      .Include(comment => comment.UserEventId) 
      .Include(comment => comment.UserId) 
      .OrderByDescending(x => x.CreatedAt) 
      .Where(x => x.CreatedAt < DateTimeOffset.Now.AsMinutes()) 
      .AsProjection<UserEvents_CreationDate.ReduceResult>(); 

     List<UserEvents_CreationDate.ReduceResult> list = processQuery(query).ToList(); 

     return (from identifier in list 
       let user = documentSession.Load<User>(identifier.UserId) 
       select Tuple.Create(identifier, user)) 
      .ToList(); 
    } 
} 

然後,所有你需要做的查詢是一樣的東西。

documentSession.QueryForRecentEvents(q => q.Where(x => x.UserId == user.Id && x.ActivityType == "asfd").Take(20)).Select(x => x.Item1); 
+0

我喜歡它,一爲包括指數! – casualtek