【问题标题】:Objectify Relationships: One-to-Many, Can I do this efficiently?对象化关系:一对多,我能有效地做到这一点吗?
【发布时间】:2012-03-07 17:11:33
【问题描述】:

我是 Objectify 的新手,我有一个简短的问题 做某事的最佳方式:

假设我有一个允许人们发送和接收的应用程序 消息(为简单起见,请考虑电子邮件)。当我的应用程序加载时,我没有 想要加载来自每个联系人的每条消息 向给定用户发送消息。那将是一种浪费。 相反,我想加载用户有消息的所有联系人 从(已读或未读),以便我可以显示联系人列表 我的应用程序,当用户点击给定的联系人时,我想加载所有 来自该联系人的消息以显示给用户。

如果不加载帐户的所有消息,我找不到执行此操作的好方法。 我阅读了关于多对一关系的 Objectify wiki,但我仍然想不到 做到这一点的好方法并不是非常低效。根据 objectify 网站推荐的方式,我必须为给定用户加载所有消息,然后解析它们以查找唯一联系人。

我正在尝试使用尽可能少的 App Engine 读取和写入,以及在哪里 可能我正在尝试使用 Smalls 而不是 Reads(总成本 在我制作这个时,运行我的应用程序是我的一个大问题)。

在 Objectify 上,我应该怎么做?

【问题讨论】:

    标签: java google-app-engine objectify


    【解决方案1】:

    这是从我对 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 的一种空间效率较低的方法。

    重要的是在发送或接收每条消息时不断更新此结构。

    【讨论】:

    • 感谢您的全面回复。我在 google-appengine-group 上询问一些后续问题。
    • 限制为 5,000,而不是 50,000 - 可能是错字。
    猜你喜欢
    • 2020-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 1970-01-01
    相关资源
    最近更新 更多