这是从我对 objectify-appengine google 组的回复中复制的:https ://groups.google.com/forum/?fromgroups#!topic/objectify-appengine/LlOyRJZRbnk
在处理您所描述的“聚合数据”时,有三个主要选项:
1) 需要时计算
你已经得出结论,我认为这是正确的,这太贵了。
2)以批处理间隔计算并存储此结果
不是很令人满意,因为它涉及延迟。另外,您不想每晚都梳理整个数据库。
3)数据变化时更新聚合
每次数据更改时,这种方法都会涉及更多工作,但这几乎肯定是您想要做的。
为每个用户创建某种联系人集合。邮件到达时,请确保该收件人存在发件人联系人。也许您还想在收件人删除发件人的最后一条消息时删除联系人。
注意不要碰到实体组事务速率限制(每秒一次写入)。我将引导您完成一些选项:
1)您可以在每个收件人中存储联系人列表:
class Person {
@Id Long id;
Set<Key<Person>> contacts;
}
如果收件人同时收到 20 个新人的邮件,这将是一个明显的问题。这几乎可以肯定是个坏主意。另一方面,查找您的联系人是谁非常快速和高效。一个小的改进是将其移动到由该人作为父对象的单独实体中,这样您就不必总是加载该数据:
class Contacts {
@Parent Key<Person> owner;
@Id long id = 1; // there's only ever one of these per person, and it should have a predictable key for fetching
Set<Key<Person>> contacts;
}
当然,Set in a single entity 为您提供了 50,000 个条目的限制。如果您首先达到 1M 实体大小限制,它可能会略小于此值。如果您的密钥约为 20 个字符,则大致相同。如果这是一个问题,您可以允许多个联系人实体,此时您有一些类似于 Brett Slatkin 的 2009 年 Google I/O 演讲中的关系索引实体模式: http ://www.youtube.com/watch?v= AgaL6NGpkB8
2)您可以在另一个方向存储联系人列表
class Person {
@Id Long id;
@Index Set<Key<Peson>> contactOf;
}
这使得找出您的联系人是谁的成本更高一些 - 您需要一个仅键查询,而不是简单的按键获取。但是您不再受实体写入速率的限制。人们每秒发送的消息可能不会超过一条,如果他们批量发送 1000 条消息,您可以在单个事务中更新 contactOf。
如上所述,您可能希望将此索引移动到单独的实体中:
class Contacts {
@Parent Key<Person> person;
@Id long id = 1; // there's only ever one of these per person, and it should have a predictable key for fetching
Set<Key<Person>> of;
}
3)您还可以将这些联系人存储在一个完全独立的实体中
class Contact {
@Parent Key<Person> person;
@Id Long id;
@Index Key<Person> owner;
}
这实际上只是一种空间效率较低的解决方案#2。
重要的是在发送或接收每条消息时不断更新此结构。