关注 AppEngine 上的数据存储模型结构 - 按日期排序关注者

Posted

技术标签:

【中文标题】关注 AppEngine 上的数据存储模型结构 - 按日期排序关注者【英文标题】:Follow datastore model structure on AppEngine - Order followers by date 【发布时间】:2011-02-10 15:43:23 【问题描述】:

在我的应用中,用户可以关注其他用户,并在他们关注的人执行活动时获取更新。

我以这种方式存储跟随关系:

class User(db.Model):
  ''' User details '''
  username = db.StringProperty()

class Contacts(db.Model):
    '''Store users contacts
       parent= User (follower)
       key_name= Users username (follower)
       contacts = A list of keys of Users that a User follows '''
    contacts = db.ListProperty(db.Key)
    last_updated = db.DateTimeProperty(auto_now=True)

获取关注者和用户关注的用户(关注者和关注者):

'''Get Users that my_user follows'''
my_user = User().all().fetch(1)
contacts = Contacts.get_by_key_name(my_user.username).contacts

''' get my_user followers - copied from an answer here on *** '''
follower_index = models.Contacts.all(keys_only=True).filter('contacts =',my_user)
follower_keys = [f.parent() for f in follower_index]
followers = db.get(follower_keys)

所以,我想按关注日期订购 my_user 关注者(我在上述模型中不跟踪),但我不确定什么是最好的方法。以下是我能想到的选项:

1) 使用“桥”模型代替 Contacts(db.Model) 的当前结构:

class Contacts(db.Model):
  follower = db.ReferenceProperty(User)
  following = db.ReferenceProperty(User)
  date_created = db.DateTimeProperty(auto_now_add=True)

但是,我仍然需要弄清楚如何确保我有唯一的追随者->关注实体:追随者=用户 1,追随者=用户 2 不应该重复。如果我对我的查询应用 2 个过滤器,我可以做到这一点。

2) 保留当前模型结构,但不是在 Contacts(db.Model) 中包含键列表,而是存储一个元组:[user_key, date_created],如下所示:

class Contacts(db.Model):
        '''Store users contacts
           parent= User (follower)
           key_name= Users username (follower)
           contacts = A list of Tuples: User.key(), date_created '''
        contacts = db.StringListProperty()
        last_updated = db.DateTimeProperty(auto_now=True)

但是,这样我将不得不处理联系人列表: - 我必须从 StringList() 中的每个字符串中提取用户键和 date_created - 然后我可以按创建日期排序用户密钥列表

3)最后一个解决方案(显然效率不高):保留原始数据库结构,并将用户关注活动存储在单独的模型中 - 每个关注操作都与 date_created 字段单独存储。仅使用此表可以按日期对用户关注者列表进行排序。这当然意味着我将执行两个数据存储放置 - 一个到 Contacts(),另一个到 FollowNewsFeed(),如下所示:

Class FollowNewsFeed(db.Model):
  ''' parent = a User follower'''
  following = db.ReferenceProperty(User)
  date_created = db.DateTimeProperty(auto_add_now=True)

非常感谢您对解决此问题的最佳方法的任何见解:)

谢谢!

【问题讨论】:

【参考方案1】:

我会使用模型从用户映射到他们的目标而不是列表:

    插入新实例或删除现有实例可能比修改一个巨大的列表并重新保存它更快。此外,随着关注的大小增加,您可以查询列表的子集,而不是全部获取(请参阅下文了解原因)。

    您可以获得额外的属性空间,并且不必担心需要重新设计和修改列表。

    不必担心列表 (each item takes up a slot, up to 5000) 的索引限制。

不幸的是,你可能会点击another limit much sooner:

A single query containing != or IN operators is limited to 30 sub-queries.

这意味着每个元素将消耗一个插槽 [例如。 in (1,2,3) = 3 个插槽]。因此,即使数量相对较少(约 30 个关注者),您也需要多次访问数据库并附加结果。

假设人们不想在他们花费数百年的时间来加载和计时的页面上发疯,您将需要对他们可以关注的人数进行某种类型的限制。如果有 100 人被跟踪,您将需要进行 4-5 次旅行,并且必须在您的应用程序内或通过 javascript 在客户端对数据进行排序。

【讨论】:

谢谢!有趣 - 我没有想到子查询限制。这是我必须解决的另一个问题,尤其是正如您提到的,我需要按日期对结果集进行排序 - 所以我需要将其全部放在一个列表中,然后再将其显示给用户..跨度> 我个人会使用 ajax 来获取数据。将其分解为过去 7 天或 100 次更新的 20 个联系人的行程,然后通过 javascript 订购和显示结果。只需确保您没有将 ajax 用于个人资料/消息列表,以便 Google 可以根据需要对其进行索引。 这意味着:(1) 获取用户联系人列表 (2) 通过将列表分解为 20 个联系人的列表来获取这些联系人的更新列表 (3) 从这些联系人获取更新,过滤按联系人姓名和 date_created(过去 7 天) (4) 如果结果列表 这样做的缺点是,如果某人在发布内容后立即拥有 1000 个关注者,那么您将存储相同的数据 1000 次。我认为在几乎可以保证超时之前,我从未设法插入超过 200 个对象。插入大量数据也会像疯了一样消耗 CPU。 我尝试实现此解决方案,循环浏览长长的联系人列表,将每个列表分块为 25 个项目,循环遍历,如果没有足够的更新,则移动日期间隔以获取较旧的更新......等等。然而,它真的很慢。如果用户有 1000 个关注者,拥有收件箱模型不需要将同一条数据存储 1000 次。它所需要的只是 1 个具有“更新接收器”的 ListProperty 的数据存储条目。看看这里的实现:***.com/questions/1630087/…

以上是关于关注 AppEngine 上的数据存储模型结构 - 按日期排序关注者的主要内容,如果未能解决你的问题,请参考以下文章

您将如何为 Twitter 等社交网站设计 AppEngine 数据存储?

如何在 Appengine 中保留数据存储实体的版本历史记录

向模型中添加一个JSONProperty以将dict保存到数据存储中

使用 Google AppEngine 创建 Java Web 服务

在 AppEngine 中思考

谷歌 Appengine 数据存储 - python