从Google App Engine NDB中删除大量实体

时间:2015-08-17 06:29:07

标签: google-app-engine google-cloud-datastore app-engine-ndb

以前的家伙在我们的Google App Engine应用中遇到了问题。目前,该应用程序正在使用NULL值保存实体,但如果我们可以清理所有值,那会更好。

这是ndb.Modal:

class Day(ndb.Model):
    date = ndb.DateProperty(required=True, indexed=True)
    items = ndb.StringProperty(repeated=True, indexed=False)
    reason = ndb.StringProperty(name="cancelled", indexed=False)

    is_hole = ndb.ComputedProperty(lambda s: not bool(s.items or s.reason))

不知何故,我们需要删除Dayis_hole的所有true

大约有4 000 000个实体,应该在服务器上删除大约2 000 000个。

到目前为止

代码

我认为首先使用此代码计算应删除的实体数量是好的:

count = Day.query(Day.is_hole != False).count(10000)

这个(限制为10 000)大约需要5秒钟才能运行。如果没有限制,则会出现DeadLineException

要删除,我已尝试过此代码:

ndb.delete_multi([key for key in Day.query(Day.is_hole != False).fetch(10000, keys_only=True)])

这个(有限制)大约需要30秒。

问题

如何更快删除所有Day is_hole != False

(我们正在使用Python)

2 个答案:

答案 0 :(得分:1)

不,没有更快的方法来删除实体 - 截止日期已修复。

但是有一些技巧。

  1. 如果你使用https://cloud.google.com/appengine/docs/python/taskqueue/你可以在第一个任务(重复)之后将一些任务放入队列生成下一个任务,你可以延长截止日期。
  2. 类似于任务队列的另一个选项是在删除一些错误记录重定向到同一个处理程序后删除,同时删除最后一条记录。需要浏览器打开直至结束。
  3. if at_least_one_bad_record:
      delete_some_records (not longer than 30s)
      spawn again this task or redirect to this handler (next call will have next 30s)
    

    请记住,如果没有更好的记录,它有退出点。它将删除所有匹配的记录而不再次单击。

答案 1 :(得分:1)

最好的方法是使用MapReduce,它将在任务队列中运行,你也可以进行分片以平行工作。这是python代码。如果您需要任何澄清,请告诉我

<强> main.py

from mapreduce import base_handler
from mapreduce import mapreduce_pipeline
from mapreduce import operation as op
from mapreduce.input_readers import InputReader
from google.appengine.api import app_identity

def deleteEntity(entity):
    yield op.db.Delete(entity)

class DeleteEntitiesPipeline(base_handler.PipelineBase):
    def run(self):
        bucket_name = (app_identity.get_default_gcs_bucket_name())
        yield mapreduce_pipeline.MapPipeline(
                "job_name", 
                "main.deleteEntity", 
                "mapreduce.input_readers.DatastoreInputReader", 
                params={
                    "entity_kind": 'models.Day',
                    "filters": [("is_hole", "=", True)],
                    "bucket_name": bucket_name
                },
                shards=5)

class StartDelete(webapp2.RequestHandler):
    def get(self):
        pipeline = DeleteEntitiesPipeline()
        pipeline.start()

application = webapp2.WSGIApplication([
    ('/deleteentities', StartDelete),
], debug=True)