【问题标题】:NDB - Most Efficient Way to Delete a List of KeysNDB - 删除键列表的最有效方法
【发布时间】:2014-09-30 02:28:32
【问题描述】:

我相信我需要使用ndb.delete_multi,但我对如何使它适用于一组特定的键以及它是否是最有效的方法感到困惑。将 Python 2.7 与 Google App Engine 结合使用。

首先,我正在收集要删除的密钥。我不想删除所有内容,只删除那些 1 小时或更长时间的条目。为此,我首先收集满足此条件的键列表。

cs = ChannelStore()
delMsgKeys = []
for x in cs.allMessages():
   current = datetime.datetime.now()
   recordTime = x.channelMessageCreated
   timeDiffSecs = (current - recordTime).total_seconds()
   timeDiff = (timeDiffSecs/60)/60
   if timeDiff >=1:
      delMsgKeys.append(x.key.id())
ndb.delete_multi(?????)

cs.allMessages() 的定义:

def allMessages(self):
        return ChannelStore.query().fetch()

首先,这总体上是最有效的方法吗?其次,如何使用通过ndb.delete_multi 语句创建的密钥列表?

---更新----

ndb.delete_multi 的问题与我传递它的键有关。在我上面发布的代码中,密钥应该存储如下:

delMsgKeys.append(x.key)

与上面的ndb.delete_multi 一起工作。

【问题讨论】:

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


    【解决方案1】:

    根据NDB documentation,您只需将密钥列表传递给ndb.delete_multi,因此根据您的代码,这应该可以工作:

    ndb.delete_multi(delMsgKeys)
    

    不过,我不确定您可以在单个 ndb.delete_multi() 调用中传递的密钥数量的限制是多少。

    对于这个查询:

    ChannelStore.query().fetch()
    

    您可以通过添加auto_now = True (more documentation here) 在创建/更新实体时添加一个实体属性来存储时间戳。然后使用timestamp 属性,您可以查询如下内容:

    sixty_mins_ago = datetime.datetime.now()- datetime.timedelta(minutes = 60)
    qry = ChannelStore.query()
    list_of_keys = qry.filter(ChannelStore.timestamp < sixty_mins_ago).fetch(keys_only = True)
    

    由于您不需要实体,因此keys_only fetch 会更便宜。当然,这段代码假设你的 ChannelStore 模型有一个 timestamp 属性,所以你的模型必须是这样的:

    class ChannelStore(ndb.model):
        #other properties go here
        timestamp = ndb.DateTimeProperty(auto_now = True)
    

    把它们放在一起,这样的东西可能适用于你上面的代码块:

    from models import ChannelStore
    from google.appengine.ext import ndb
    from datetime import datetime, timedelta
    # other imports
    
    def delete_old_entities():
        sixty_mins_ago = datetime.now() - timedelta(minutes = 60)
        qry = ChannelStore.query()
        qry = qry.filter(ChannelStore.timestamp < sixty_mins_ago)
        list_of_keys = qry.fetch(keys_only = True)
        ndb.delete_multi(list_of_keys)
    

    如果您必须删除大量密钥并且使用 ndb.delete_multi 调用遇到某种 API 限制,您可以将 delete_old_entities() 方法更改为以下内容:

    def delete_old_entities():
        sixty_mins_ago = datetime.datetime.now() - datetime.timedelta(minutes = 60)
        qry = ChannelStore.query()
        qry = qry.filter(ChannelStore.timestamp < sixty_mins_ago)
        list_of_keys = qry.fetch(keys_only = True)
    
        while list_of_keys:
            # delete 100 at a time
            ndb.delete_multi(list_of_keys[:100])
            list_of_keys = list_of_keys[100:]
    

    【讨论】:

    • 感谢您的回复。在进入时间部分之前,我想评论一下 ndb.delete_multi。我确实浏览了他们的文档,和你一样,我觉得我所要做的就是传递钥匙。但是,它给出了一个错误。基本上错误归结为这一行:“AttributeError:'long'对象没有属性'delete_async'”
    • 我发现了 delete_multi 的部分问题。我只需要传递“key”而不是“key_id”。我将在上面发布更新。
    • 我确实存储了一个日期时间属性。我确实看到了您对代码的建议,但我不确定它是否可以保存任何内容。我仍在进行查询,然后返回 ndb.delete_multi。你看到我发布的代码提高了效率吗?
    • 我认为会让事情变得更高效(真的更便宜)的最重要的事情是你在你的代码中获取整个实体,而keys_only fetch 会更便宜。您不需要整个实体来删除它,但是您需要为所有这些数据存储读取付费,而keys_only 查询是free。此外,您的代码会获取 每个 实体并稍后手动过滤,而我认为在开始时仅获取具有特定过滤器的实体会更快。
    • 添加,您可以计时是否过滤之前或之后的步骤并查看差异 - 我的猜测是它不会很重要。在任何情况下,您都应该执行 keys_only 查询以节省资金。尝试 appstats 以查看任何差异,尤其是 RPC 调用,这通常是应用引擎应用中的速率限制步骤。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-02
    • 2016-02-11
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多