我正在与Raven玩一下,试图找出为类似Twitter的场景建模对象的最佳方法。到目前为止,我已经提出了一些选择,但不确定哪一个是最好的。
public class User{
public string Id{get;set;}
public List<string> Following{get;set;}
public List<string> Followers{get;set;}
}
User对象简单明了,只是一个ID和一系列ID,供我关注的人和跟随我的人使用。 Feed设置是我需要帮助的地方,从我关注的用户处获取所有帖子。
这会根据用户ID搜索我关注的所有帖子。
public class Post{
public string UserId{get;set;}
public string Content{get;set;}
}
public class Posts : AbstractIndexCreationTask<Post>{
public Posts(){
Map = results => from r in results
select new{
r.UserId
};
}
}
var posts = session.Query<Post,Posts>().Where(c=>c.UserId.In(peopleImFollowing));
这是显而易见的路线,但闻起来很糟糕。该查询导致发送给Lucene的一堆OR语句。 Raven将处理大约1024的上限,因此任何一个用户都不能超过1000人。
public class Post{
public string UserId{get;set;}
public string RecipientId{get;set;}
public string Content{get;set;}
}
foreach(string followerId in me.Followers){
session.Store(new Post{
UserId = me.UserId,
RecipientId = followerId,
Content = "foobar" });
}
这很容易理解,但很容易查询,但似乎会创建太多的文件......也许这无关紧要?
到目前为止,我最喜欢这个。
public class Post{
public string UserId{get;set;}
public List<string> Recipients{get;set;}
public string Content{get;set;}
}
public class Posts : AbstractIndexCreationTask<Post>{
public Posts(){
Map = results => from r in results
select new{
UserId = r.UserId,
Recipient = r.Recipients
}
}
}
session.Store(new Post{
UserId = me.Id,
Recipients = me.Followers,
Content = "foobar"
});
var posts = session.Query<Post,Posts>().Where(c=>c.Recipient == me.Id);
这似乎是最好的方式,但我之前从未与Lucene合作过。如果有人拥有10,000名粉丝,这对索引会有问题吗?如果我们想发布一个发送给每个用户的消息怎么办?也许有另一种方法?
答案 0 :(得分:1)
从我的角度来看,只有选项1确实有效,如果你想支持超过1024个用户,你可能想调整RavenDB如何与lucene对话。
选项2和选项3 没有考虑到在您关注新用户后,您希望他们的旧推文显示在您的时间轴中。同样,您还希望在取消关注后,这些推文会从您的时间轴中消失。如果你想用这两种方法中的一种来实现它,你需要在'follow'操作中复制它们的所有推文,并在'unfollow'上删除它们。这将使跟随/取消关注非常昂贵的操作,并且它也可能失败(如果包含部分推文的服务器在您执行此操作时不可用,该怎么办?)。
选项2 还有一个巨大的缺点,就是它会产生大量的重复数据。想想拥有数百万粉丝和数千个帖子的知名用户。然后将其与成千上万的着名用户相乘......甚至Twitter也无法处理这么多数据。
选项3 还存在这样的问题:对索引的查询变慢,因为每个lucene文档都有这个“收件人”字段,可能有数百万个值。你有数万亿的文件...不,我不是一个lucene专家,但我认为它不能足够快地显示时间线(甚至忽略你不是唯一想要显示时间线的并发用户)。
正如我上面所说,我认为只有选项1才有效。也许其他人有更好的方法。好问题顺便说一句。