App Engine 中的 db.ReferenceProperty() 与 ndb.KeyProperty

Posted

技术标签:

【中文标题】App Engine 中的 db.ReferenceProperty() 与 ndb.KeyProperty【英文标题】:db.ReferenceProperty() vs ndb.KeyProperty in App Engine 【发布时间】:2013-05-24 07:30:59 【问题描述】:

ReferenceProperty 在处理两个模块之间的引用时非常有帮助。狐狸例子:

class UserProf(db.Model):
    name = db.StringProperty(required=True)

class Team(db.Model):
    manager_name = db.ReferenceProperty(UserProf, collection_name='teams')
    name = db.StringProperty(required=True)
要使用团队实例获取“manager_name”,我们使用 team_ins.manager_name。 要获取由特定用户实例管理的“团队”,我们使用 user_instance.teams 并进行迭代。

它看起来不是很容易理解吗?

在使用 NDB 做同样的事情时,我们必须修改

db.ReferenceProperty(UserProf, collection_name='teams') --> ndb.KeyProperty(kind=UserProf)

team_ins.manager_name.get() 会给你经理名字

要获得由特定用户管理的所有团队,我们必须这样做

for team in Team.query(Team.manager_name == user_ins.key): 
    print "team  name:", team.name

正如您所见,在 db 中处理这些场景看起来比在 ndb 中更容易和可读。

ndb 中删除 ReferenceProperty 的原因是什么? 即使是 db 的查询 user_instance.teams 也会执行与 ndb 的 for 循环中相同的操作。但在 ndb 中,我们明确提到了使用 for 循环。 当我们执行 user_instance.teams 时,幕后发生了什么?

提前谢谢..

【问题讨论】:

【参考方案1】:

蒂姆解释得很好。我们发现一个常见的反模式是使用引用属性并一次加载它们,因为符号“entity.property1.property2”并没有清楚地表明第一个点会导致数据库“获取”操作。因此,我们通过强制您编写“entity.property1.get().property2”使其更加明显,并且我们通过简单地说“entity.property1.get_async”使批量预取变得更容易(没有尼克博客中的复杂解决方案) ()” 用于一堆实体 - 这会将单个批处理获取操作排队而不阻塞结果,并且当您下次使用“entity.property1.get().property2”引用这些属性中的任何一个时,这不会启动另一个get 操作,但只是等待该批处理完成(第二次执行此操作时,批处理获取已经完成)。此外,这种方式的进程内和内存缓存集成是免费的。

【讨论】:

谢谢。 ndb 与 db 相同,但它是明确的,用户会知道有 get() 操作。在这种情况下没有性能改进。我已经阅读了有关 ndb async 的信息,还没有使用它。 @Tim 和 Guido,您能否推荐任何使用 ndb 编写的示例应用程序,类似于code.google.com/p/google-app-engine-samples 中的应用程序。以及在基于 ndb 的应用程序中遵循的最佳实践。这会有很大帮助。谢谢。 调用entity.keyproperty.get().somevalue1 将第一次获取keyproperty 引用的实体,随后entity.keyproperty.get().somevalue2entity.keyproperty.get().somevalue3 将不会进行db 调用??? Okay....由于上下文是相同的(在相同的请求中并且如果没有初始化新线程),当第一次调用 get 时,实体将保存在上下文缓存中,并且相同的实体将在随后的 get 函数调用中返回,因此没有新的 db 调用。有关上下文缓存的更多信息,请参阅此链接 (cloud.google.com/appengine/docs/python/ndb/cache#context)。【参考方案2】:

我不知道为什么 Guido 没有实现引用属性的答案。

但是我发现使用 pre_fetch_refprops http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine 花了很多时间(通过使用 get_value_for_datastore 抓取所有键来预获取所有引用属性),然后它对键执行 get_multi。

这大大提高了效率。

此外,如果引用的对象不存在,则在尝试获取该对象时会出错。

如果你腌制一个有引用的对象,你最终腌制的次数可能比你计划的要多得多。

所以我发现除了一种情况,你有一个实体并且你想用 .name 类型的访问器来获取引用的对象,你必须跳过各种障碍来防止引用的实体被获取。

【讨论】:

谢谢。希望Guido本人能回答这个问题!:)

以上是关于App Engine 中的 db.ReferenceProperty() 与 ndb.KeyProperty的主要内容,如果未能解决你的问题,请参考以下文章

App Engine 中的模板目录是如何设置的?

将参数传递给 app.yaml Google App Engine 中的 php

NodeJS 中的 Google App Engine 日志记录

Google App Engine / Datastore / Flask / Python app 中的内存泄漏

数据存储区中的 Google App Engine 版本控制

Google App Engine 中的 Django 模板语法错误