0

〜 800 エンティティのテーブルを表示しようとしていますが、非常に遅くなるのを防ぐのに問題があります。(15 ~ 20 秒遅くなります。) memcache を正常に実装しましたが、子エンティティごとに親モデルを参照しているため、800 ごとに datastore_v3.Get が発生し、非常に遅くなります。

次に、Nick Johnson のReferenceProperty プリフェッチを実装しましたが、次のエラーを解決できません。

[... 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

モデル:

関連する 2 つのモデルは次のとおりです。

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 の効率的なモデル memcachingReferenceProperty 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」の反復可能な「entry」だけでなく、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'

何が欠けているか、台無しになっていますか?助けていただければ幸いです。

4

1 に答える 1

1

ジェド、あなたはそれを正しくやっています:)

2 つの改善点:

  1. プリフェッチの戻り値は使用されておらず、companylist はその場で変更されるため、割り当てる必要はありません。
  2. 参照プロパティが設定されていない場合を処理するために、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

私たちのコードが実行しているもう 1 つの重鎖はしご操作は、各オブジェクトの ref_set に対する count() です。これは、近い将来、オブジェクトの値をキャッシュするものに置き換えます。

于 2012-10-12T23:19:28.747 に答える