初期化作業を行うために、Google AppEngine データストアのすべてのエントリを読み取る必要があります。多くのエンティティ (現在 80k) があり、これは増え続けています。30 秒のデータストア クエリ タイムアウト制限に達し始めています。
データストアでこれらのタイプの巨大な読み取りを分割する方法に関するベスト プラクティスはありますか? 例はありますか?
初期化作業を行うために、Google AppEngine データストアのすべてのエントリを読み取る必要があります。多くのエンティティ (現在 80k) があり、これは増え続けています。30 秒のデータストア クエリ タイムアウト制限に達し始めています。
データストアでこれらのタイプの巨大な読み取りを分割する方法に関するベスト プラクティスはありますか? 例はありますか?
これにはいくつかの方法で対処できます。
タイムアウトが 30 秒ではなく 10 分のタスク キューでコードを実行します(実際には 60 秒に近い)。これを行う最も簡単な方法は、DeferredTask
.
警告: DeferredTask はシリアライズ可能でなければならないため、複雑なデータを渡すのは困難です。また、内部クラスにしないでください。
バックエンドを参照してください。バックエンド インスタンスによって処理されるリクエストには時間制限がありません。
最後に、大きなタスクを分割して並行して実行する必要がある場合は、mapreduceを参照してください。
StackExchange に関するこの回答は、私に役立ちました。
私のために動作するように少し変更する必要がありました:
def loop_over_objects_in_batches(batch_size, object_class, callback):
num_els = object_class.count()
num_loops = num_els / batch_size
remainder = num_els - num_loops * batch_size
logging.info("Calling batched loop with batch_size: %d, num_els: %s, num_loops: %s, remainder: %s, object_class: %s, callback: %s," % (batch_size, num_els, num_loops, remainder, object_class, callback))
offset = 0
while offset < num_loops * batch_size:
logging.info("Processing batch (%d:%d)" % (offset, offset+batch_size))
query = object_class[offset:offset + batch_size]
for q in query:
callback(q)
offset = offset + batch_size
if remainder:
logging.info("Processing remainder batch (%d:%d)" % (offset, num_els))
query = object_class[offset:num_els]
for q in query:
callback(q)