【问题标题】:FRIENDS Table Datastore Design + App Engine PythonFRIENDS 表数据存储设计 + App Engine Python
【发布时间】:2012-07-13 18:16:17
【问题描述】:

在我的应用程序中,我们需要在数据存储区中开发一个 FRIENDS 关系表。当然,我想到的一个快速解决方案是:

user     = db.ReferenceProperty(User, required=True, collection_name='user')
friend   = db.ReferenceProperty(User, required=True, collection_name='friends')

但是,当朋友列表增长到一个巨大的数字,比如几千或更多时会发生什么?这会不会太低效了?

性能始终是我们的首要任务。这是非常需要的,因为我们将没有更多的东西来遵循这种类似的关系设计。

请就在 App Engine Python 环境中使用数据存储区设计 FRIENDS 关系表的最佳方法提供建议。

编辑 除了 FRIENDS 关系,FOLLOWER 关系也将被创建。而且我相信在大多数情况下,所有这些关系都足以成为查询,因为我的应用程序往往是面向社交媒体的。

例如,如果我关注一些用户,我将获得关于他们将要做什么等的新闻提要更新。随着时间的推移,活动会增加。至于有多少用户,我还不能回答,因为我们还没有上线。但我预计随着我们的发展,将会有数百万用户。

希望这将有助于获得更具体的建议,或者是否有替代这种方法的方法?

【问题讨论】:

  • 这样的事情是否有效取决于很多事情。您将拥有多少用户(作为上限)?用户会有多少关系?您如何在应用程序中使用关系?这些关系多久更新一次?
  • @Dan Holevoet,感谢您的提问。我已经更新了描述。请提供一些建议,因为这对我们开始使用正确的方法开始非常重要。

标签: python google-app-engine google-cloud-datastore


【解决方案1】:

您的 FRIENDS 模型(可能还有您的 FOLLOWERS 模型)应该可以很好地扩展。系统中的棘手部分实际上是聚合来自用户所有朋友和关注者的内容。

根据您在帖子中描述的表格,查询用户列表的时间为 O(N),其中 N 是朋友的数量。但是,这些查询中的每一个都需要另一个 O(N) 操作来检索朋友共享的内容。每次用户想要查看最近的内容时,这都会导致 O(N^2)。这个特定的查询不好有两个原因:

  1. 在为数百万用户设计系统时,您不希望在核心算法中看到 O(N^2) 运算。
  2. App Engine 倾向于限制此类查询。具体来说,您需要使用 IN 关键字来获取共享项目列表,这不适用于超过 30 个朋友。

对于这个特殊问题,我建议创建另一个表,将每个用户链接到每个共享内容。像这样的:

class SharedItems(db.Model):
  user = db.ReferenceProperty(User, required=True) # logged-in user
  from = db.ReferenceProperty(User, required=True) # who shared it
  item = db.ReferenceProperty(Item, required=True) # the item itself
  posted = db.DateTimeProperty() # when it was shared

在渲染更新流时,您需要一个 O(N) 查询(N 是您要显示的项目数)来查找与用户共享的所有项目(按日期降序排列) .保持 N 小,以尽可能快地保持这一速度。

分享一个项目需要创建 O(N) SharedItems,其中 N 是发布者拥有的朋友和关注者的数量。如果这个数字太大而无法在单个请求中处理,请将其分片到任务队列或后端。

【讨论】:

  • 非常感谢您的建议。这当然有助于提供一些额外的想法并牢记查询效率。我也可以将此与我的应用程序的许多情况联系起来,因为我们正在努力使我们的应用程序尽可能面向社交媒体。再次感谢!
  • 所以当用户获得新的关注者时,它必须更新 shareditems 实体并插入一堆行?此外,如果用户取消关注某人,它必须从 shareditems 中删除一堆行?
【解决方案2】:

propertylist 是在 GAE 中获得廉价/简单索引的好方法。 但正如您正确识别的那样,存在一些限制。

  1. 整个实体的索引大小是有限的(我认为目前是 5000)。所以每个 propertyList 值都需要一个索引。所以基本上属性列表大小

  2. 如此庞大的财产清单的序列化成本很高! 带回一个 2Mb 的实体很慢……而且会消耗 CPU。

如果期望较大的 propertyIndex 则不要这样做。

另一种方法是创建一个为关系建模的 JOIN 表

 class Friends(db.Model):
  user = db.ReferenceProperty(User, required=True) # logged-in user
  from = db.ReferenceProperty(User, required=True) # who shared it

只是一个有 2 个键的实体。 这允许简单的查询来查找用户的所有朋友。

select from friends where user = : me

找到我是朋友的所有用户。

select from friends where friend = : me

因为它返回一个密钥,你可以做一个批量 get(keylist) 来获取实际的朋友详细信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    • 2011-05-26
    • 2013-05-17
    • 2011-09-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多