Python 如何通过预取ReferenceProperty属性来防止过度RPC调用?

Python 如何通过预取ReferenceProperty属性来防止过度RPC调用?,python,google-app-engine,memcached,jinja2,Python,Google App Engine,Memcached,Jinja2,我试图显示一个包含约800个实体的表,但在保持速度方面存在问题。(大约慢15-20秒)我成功地实现了memcache,但是因为我为每个子实体引用了父模型,所以它仍然会导致800个实体中的每个实体都有一个datastore_v3.Get,速度非常慢 然后我实现了Nick Johnson的,但无法解决以下错误: [... snipped ...] File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppE

我试图显示一个包含约800个实体的表,但在保持速度方面存在问题。(大约慢15-20秒)我成功地实现了memcache,但是因为我为每个子实体引用了父模型,所以它仍然会导致800个实体中的每个实体都有一个datastore_v3.Get,速度非常慢

然后我实现了Nick Johnson的,但无法解决以下错误:

[... snipped ...]
File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/webapp2/webapp2.py", line 570, in dispatch
  return method(*args, **kwargs)
File "/myurl/mypythoncode.py", line 67, in get
  prefetch_refprops(entitylist, ChildModel.parent_program.name)
File "/myurl/mypythoncode.py", line 36, in prefetch_refprops
  fields = [(entity, prop) for entity in entities for prop in props]
TypeError: 'NoneType' object is not iterable
型号:

以下是两个相关模型:

class ParentModel(db.Model):
  name = db.StringProperty()
  # currently 109 of these

class ChildModel(db.Model):
  name = db.StringProperty()
  parent_program = db.ReferenceProperty(ParentModel)
  website = db.StringProperty()
  # currently 758 of these
Python代码:

在我的Python代码中,我使用了Nick Johnson的和for技术。(我在下面包括了ReferenceProperty预取,但没有包括memcaching代码。)

Jinja2模板:

我的Jinja2模板引用了“entitylist”中的iterable“entry”,还引用了parent_program.name和parent_program.key().id()

以及其他变体,包括“.name”和“.key().id()”。当我使用“.key().id()”时,我得到一个错误:

AttributeError: 'ReferenceProperty' object has no attribute 'key'

我错过了什么或搞砸了什么?我真的很感激任何帮助

杰德,你做得对:)

两项改进:

  • 您不需要分配预回迁的返回值,因为它没有被使用,并且公司列表将被修改到位
  • 我使用一个稍加修改的prefetch_refprops版本来处理引用属性未填充的情况

    def prefetch_refprops(entities, *props):
        fields = [(entity, prop) for entity in entities for prop in props]
        ref_keys_all = [prop.get_value_for_datastore(x) for x, prop in fields]
        ref_keys = [ref_key for ref_key in ref_keys_all if ref_key is not None]
        ref_entities = dict((x.key(), x) for x in db.get(set(ref_keys)))
        for (entity, prop), ref_key in zip(fields, ref_keys_all):
            if ref_key and ref_entities[ref_key]:
                prop.__set__(entity, ref_entities[ref_key])
            else:
                prop.__set__(entity, None)
        return entities
    
  • 我们在生产代码中使用它,它会带来真正的不同。下面是一个在构建模板值的代码位上打开/关闭预取的示例

    (run:   real_time, Get #rpcs, RunQuery #rpcs)
    Before:   5044 ms,       132,    101
    After:    2214 ms,        53,     11
    

    我们的代码正在执行的另一个重链阶梯操作是每个对象的ref_集上的count(),我们将在不久的将来用缓存对象上的值来替换它。

    删除第一行
    entityref=prefetch\u refprops(entitylist,ChildModel.parent\u program.name)
    entitylist
    在第一次通过时设置为“无”,因此预取失败。谢谢,我已经解决了这个问题。但现在我得到了“prefetch\u refprops(companylist,ChildModel.parent\u program.name)”的“AttributeError:'str'对象没有属性'get\u value\u for_datastore'”。这似乎有些奇怪,因为它实际上与Nick在其示例中使用的完全相同。好的,我现在修复了它,将其更改为“prefetch_refprops(companylist,ChildModel.parent_program)”。我不会再犯错误了,但感觉我还是做得不对……谢谢,坎比。我最终采用了一种不同的方法,Guido在这里概述了这种方法:但它确实有效!
    entityref = prefetch_refprops(entitylist, ChildModel.parent_program)
    
    AttributeError: 'ReferenceProperty' object has no attribute 'key'
    
    def prefetch_refprops(entities, *props):
        fields = [(entity, prop) for entity in entities for prop in props]
        ref_keys_all = [prop.get_value_for_datastore(x) for x, prop in fields]
        ref_keys = [ref_key for ref_key in ref_keys_all if ref_key is not None]
        ref_entities = dict((x.key(), x) for x in db.get(set(ref_keys)))
        for (entity, prop), ref_key in zip(fields, ref_keys_all):
            if ref_key and ref_entities[ref_key]:
                prop.__set__(entity, ref_entities[ref_key])
            else:
                prop.__set__(entity, None)
        return entities
    
    (run:   real_time, Get #rpcs, RunQuery #rpcs)
    Before:   5044 ms,       132,    101
    After:    2214 ms,        53,     11