我正在尝试显示一个包含约800个实体的表格,并且在保持它真正慢的问题上存在问题。 (比如15-20秒慢。)我成功实现了memcache,但因为我引用了每个子实体的父模型,所以它仍然会导致每个800的datastore_v3.Get并且速度非常慢。
然后我实施了Nick Johnson的ReferenceProperty prefetching并且无法解决以下错误:
[... 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的efficient model memcaching和ReferenceProperty prefetching技巧。 (我在下面列出了ReferenceProperty预取,但不包括memcaching代码。)
class AllEntities(webapp2.RequestHandler):
def get(self):
entitylist = deserialize_entities(memcache.get("entitylist"))
entityref = prefetch_refprops(entitylist, ChildModel.parent_program.name)
if not entitylist:
entitylist = ChildModel.all().fetch(None)
entityref = prefetch_refprops(entitylist, ChildModel.parent_program.name)
memcache.set("entitylist", serialize_entities(entitylist))
context = {
'entitylist': entitylist,
}
self.response.out.write(template.render(context))
def prefetch_refprops(entities, *props):
fields = [(entity, prop) for entity in entities for prop in props]
ref_keys = [prop.get_value_for_datastore(x) for x, prop in fields]
ref_entities = dict((x.key(), x) for x in db.get(set(ref_keys)))
for (entity, prop), ref_key in zip(fields, ref_keys):
prop.__set__(entity, ref_entities[ref_key])
return entities
Jinja2模板:
我的Jinja2模板引用了“entitylist”中的可迭代“条目”,还引用了parent_program.name和parent_program.key()。id()
{% for entry in entitylist %}
<tr>
<td><a href="{{ entry.website}}">{{ entry.website }}</a></td>
<td><a href="/urlcategory/view?entityid={{ entry.parent_program.key().id() }}">{{ entry.parent_program.name }}</td>
</tr>
{% endfor %}
我已经更换了这一行:
entityref = prefetch_refprops(entitylist, ChildModel.parent_program.name)
与
entityref = prefetch_refprops(entitylist, ChildModel.parent_program)
以及其他包含“.name”和“.key()。id()”的变体。当我使用“.key()。id()”时,我收到错误:
AttributeError: 'ReferenceProperty' object has no attribute 'key'
我错过了什么或搞砸了什么?我真的很感激任何帮助!
答案 0 :(得分:1)
两项改进:
我使用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_set上的count(),我们将在不久的将来替换对象上的值。