2

App Engine で初めて memcache を使用しようとしましたが、「PicklingError」が発生しました。

memcache を最初に試したのは、データストアからコンテンツを取得するサイトのホームページです。

def get(self):
    content = memcache.get('home:content')
    if content is None:
        all_content = Content.all()
        all_content.order("-views")
        all_content.filter('published =', True)
        content = all_content.run(batch_size=5, limit=5)
        memcache.add(key='home:content', value=content, time=120)

(これは、コンテンツ Query オブジェクトを memcache に入れようとしなくても問題なく動作することに注意してください。最後の行 (memcache.add...) でヒットするエラーは次のとおりです。

PicklingError: Pickling of datastore_query.Batcher is unsupported.

コンテンツのモデルは次のとおりです。

class Content(db.Model):
    category = db.StringProperty(required = True)
    content_type = db.StringProperty(required = True)
    published = db.BooleanProperty(default = False)
    title = db.StringProperty(required = True)
    abstract = db.TextProperty(required = True)
    summary = db.TextProperty(required = True)
    URL = db.LinkProperty(required = True)
    youtube_id = db.StringProperty(required = False)
    thumbnail = db.LinkProperty(required = True)
    post_author = db.StringProperty(required = True)
    author_url = db.LinkProperty(required = False)
    date_post = db.DateTimeProperty(required = True, auto_now_add = True)
    date_source = db.DateTimeProperty(required = False)    
    # todo: split out to use decent shardedcounter approach
    views = db.IntegerProperty(default = 0)
    up_votes = db.IntegerProperty(default = 0)
    down_votes = db.IntegerProperty(default = 0)    
    def votes(self):
        return self.up_votes - self.down_votes

PicklingError とは何か、それが Query オブジェクトを memcache に格納しようとすることにどのように関係するのかを理解するのに苦労しています。私の質問: 私は何を間違っていますか? これは、イテレータをキャッシュしようとしているからですか? Query オブジェクトをキャッシュし、ページの読み込みごとに .run() を呼び出す必要があることに価値はありますか?

4

1 に答える 1

2

のソースを見てくださいmemcache

簡単に言えば、これは、値を単純な方法でシリアル化する必要があるために発生するため、デフォルトではpickle(実際にはcPickle) を使用して、渡すオブジェクトをシリアル化します。

add呼び出されると、_set_with_policyが呼び出され、続いて が呼び出されます_set_multi_async_with_policy。では_set_multi_async_with_policy、キーと値のペアが as として渡され、ループでシリアル化されmappingます。

for key, value in mapping.iteritems():
  server_key = _key_string(key, key_prefix, user_key)
  stored_value, flags = _validate_encode_value(value, self._do_pickle)

ヘルパー メソッドでは、渡されたオブジェクトが、、_validate_encode_valueなどの認識可能なものではない場合、メソッドはオブジェクトをピクルしようとします。intboolstr

else:
  stored_value = do_pickle(value)
  flags |= TYPE_PICKLED

更新: run を呼び出すと、クエリに含まれる特定のオブジェクトを含むiterator オブジェクトが返されます。結果だけをピクルしたい場合は、このイテレータを次の方法でリストにキャストできます

content = list(all_content.run(batch_size=5, limit=5))

他の部分を残しておきたい場合は、ある種のカスタム ピックラーが必要です。あなたが見ることができるようにBatcher

  def __getstate__(self):
    raise pickle.PicklingError(
        'Pickling of datastore_query.Batch is unsupported.')

で定義されているほとんどのクラス(クエリ動作の大部分を定義しているクラスとまったく同じクラス) は、 whenが呼び出されたときにdatastore_queryをスローすることにより、ピッキングを強く思いとどまらせます。あなたがそれをいじったことがなく、オブジェクトをピクルしたりアンピクルしたりするのに役立つカスタムメソッドである場合。PicklingError__getstate____getstate____setstate__

于 2012-11-23T18:50:08.350 に答える