2

input_reader 用の新しい Google App Engine MapReduce ライブラリ フィルタで遊んでいます。ndb.Key でフィルタする方法を知りたいです。

この投稿を読んで、フィルタ タプルで datetime、string、int、float を使用しましたが、ndb.Key でフィルタするにはどうすればよいですか?

ndb.Key でフィルタリングしようとすると、次のエラーが発生します。

BadReaderParamsError: Expected Key, got u"Key('Clients', 406)"

またはこのエラー:

TypeError: Key('Clients', 406) is not JSON serializable

ndb.Key オブジェクトと ndb.Key の文字列表現を渡そうとしました。

これが私の2つのフィルタータプルです:

サンプル 1:

input_reader': {
  'input_reader': 'mapreduce.input_readers.DatastoreInputReader',
  'entity_kind': 'model.Sales',
  'filters': [("client","=", ndb.Key('Clients', 406))]
}

サンプル 2:

input_reader': {
  'input_reader': 'mapreduce.input_readers.DatastoreInputReader',
  'entity_kind': 'model.Sales',
  'filters': [("client","=", "%s" % ndb.Key('Clients', 406))]
}
4

4 に答える 4

2

これは少しトリッキーです。

Google Code のコードを見ると、JSON シリアライゼーション/デシリアライゼーションで特別なケースの処理を行うクラスを決定mapreduce.modelする dict を定義していることがわかります。デフォルトでは、datetime のみです。JSON_DEFAULTSしたがって、ndb.Keyそこにクラスをモンキー パッチし、そのシリアル化/逆シリアル化を実行する関数を提供できます。次のようなものです。

from mapreduce import model

def _JsonEncodeKey(o):
  """Json encode an ndb.Key object."""
  return {'key_string': o.urlsafe()}

def _JsonDecodeKey(d):
  """Json decode a ndb.Key object."""
  return ndb.Key(urlsafe=d['key_string'])

model.JSON_DEFAULTS[ndb.Key] = (_JsonEncodeKey, _JsonDecodeKey)
model._TYPE_IDS['Key'] = ndb.Key

パッチを適用するために、最後の 2 行を繰り返す必要がある場合もありmapreduce.lib.pipeline.utilます。

また、これを行う場合は、mapreduce の任意の部分を実行するすべてのインスタンスでこれが確実に実行されるようにする必要があることに注意してください。これを行う最も簡単な方法は、上記の登録コードをインポートするラッパー スクリプトを作成することです。 、 app.yamlmapreduce.main.APPの URL をオーバーライドして、ラッパーを指すようにします。mapreduce

于 2013-05-07T16:13:19.577 に答える
1

DatastoreInputReaderキーベースのフィルターをデコードする方法を知っている に基づいて、独自の入力リーダーを作成します。

class DatastoreKeyInputReader(input_readers.DatastoreKeyInputReader):
    """Augment the base input reader to accommodate ReferenceProperty filters"""
    def __init__(self, *args, **kwargs):
        try:
            filters = kwargs['filters']
            decoded = []
            for f in filters:
                value = f[2]
                if isinstance(value, list):
                    value = db.Key.from_path(*value)
                decoded.append((f[0], f[1], value))
            kwargs['filters'] = decoded
        except KeyError:
            pass

        super(DatastoreKeyInputReader, self).__init__(*args, **kwargs)

オプションとしてフィルターを渡す前に、フィルターでこの関数を実行します。

def encode_filters(filters):
    if filters is not None:
        encoded = []
        for f in filters:
            value = f[2]
            if isinstance(value, db.Model):
                value = value.key()
            if isinstance(value, db.Key):
                value = value.to_path()
            entry = (f[0], f[1], value)
            encoded.append(entry)
        filters = encoded

    return filters
于 2013-05-07T16:11:46.900 に答える
1

to_old_key() および from_old_key() メソッドを知っていますか?

于 2013-05-08T14:52:08.597 に答える