我想知道设计社交应用程序的最佳方式是什么,其中成员使用Google AppEngine进行活动并关注其他成员的活动。
更具体地说,假设我们有这些实体:
困难的部分是关注朋友的活动,这意味着汇总所有朋友的最新活动。 通常情况下,这将是活动表和你的朋友列表之间的连接,但这不是一个可行的appengine设计,因为没有连接模拟它将需要激活N个查询(其中N是朋友的数量),然后在内存中合并 - 非常昂贵,可能会超过要求的截止日期......)
我目前正在考虑使用收件箱队列实现此功能,其中新活动的创建将触发后台进程,该进程将新活动的密钥放在每个后续用户的“收件箱”中:
我很高兴听到有关此设计或其他建议等的想法。
答案 0 :(得分:25)
看看Building Scalable, Complex Apps on App Engine(pdf),这是Brett Slatkin在Google I / O上发表的精彩演讲。他解决了构建像Twitter这样的可扩展消息传递服务的问题。
以下是使用list属性的解决方案:
class Message(db.Model):
sender = db.StringProperty()
body = db.TextProperty()
class MessageIndex(db.Model):
#parent = a message
receivers = db.StringListProperty()
indexes = MessageIndex.all(keys_only = True).filter('receivers = ', user_id)
keys = [k.parent() for k in indexes)
messages = db.get(keys)
此仅密钥查询查找接收方等于您指定的接收方的消息索引,而不反序列化和序列化接收方列表。然后使用这些索引仅获取所需的消息。
这是错误的方式:
class Message(db.Model):
sender = db.StringProperty()
receivers = db.StringListProperty()
body = db.TextProperty()
messages = Message.all().filter('receivers =', user_id)
这是低效的,因为查询必须解包查询返回的所有结果。因此,如果您在每个接收者列表中返回100条消息,其中包含1,000个用户,则必须反序列化100,000(100 x 1000)个列表属性值。数据存储延迟和CPU的方式太贵了。
起初我对所有这些感到非常困惑,所以我写了short tutorial about using the list property。享受:)
答案 1 :(得分:7)
我不知道它是否是社交应用程序的最佳设计,但当公司被Google收购时,jaiku是ported to App Engine的原始创建者,{}所以这应该是合理的。
请参阅design_funument.txt中的 Actors and Tigers and Bears,Oh My!部分。实体在common/models.py中定义,查询在common/api.py。
答案 2 :(得分:1)
messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])
我认为ndb.TextProperty" body"不能与投影一起使用,因为没有编入索引。预测仅支持索引属性。 有效的解决方案是维护2个表:Message和MessageIndex。
答案 3 :(得分:0)
我认为现在可以通过NDB中的新投影查询来解决这个问题。
class Message(ndb.Model):
sender = ndb.StringProperty()
receivers = ndb.StringProperty(repeated=True)
body = ndb.TextProperty()
messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])
现在您不必处理反序列化列表属性的昂贵成本。