【问题标题】:How to delete all datastore in Google App Engine?如何删除 Google App Engine 中的所有数据存储区?
【发布时间】:2010-11-06 22:42:42
【问题描述】:

有人知道如何删除Google App Engine 中的所有数据存储区吗?

【问题讨论】:

  • db.delete(db.Query(keys_only=True))。更多细节在这里stackoverflow.com/a/10856555/290340
  • 正如下面@systempuntoout 所指出的,GAE 现在有一个Datastore Admin,可以让您在不进行任何编码的情况下批量删除实体,等等。该功能需要在这里浮出水面,而不是隐藏在第三条评论中。
  • Datastore Admin 不起作用(页面将 iframe 加载到不存在的主机),所以我们仍然需要使用 db.delete 方法。
  • 要删除开发服务器上的所有数据,请在 cmd 提示符下发出以下命令:/path/to/google_appengine/dev_appserver.py --clear_datastore yes myappname/ 其中 myappname 是您的目录,其中包含应用程序的 app.yaml 文件。您需要 cd 到此目录路径.. 学分:Steven Almeroth 和 Melllvar 在下面给出答案

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


【解决方案1】:

如果您谈论的是实时数据存储,请打开您的应用的仪表板(在 appengine 上登录)然后打开数据存储 --> 数据查看器,选择您要删除的表的所有行,然后点击删除按钮(您必须为所有表格执行此操作)。 您可以通过 remote_api 以编程方式执行相同的操作(但我从未使用过它)。

如果您说的是 development datastore,您只需删除以下文件:"./WEB-INF/appengine-generated/local_db.bin" 。下次运行开发服务器时会再次为您生成该文件,您将拥有一个清晰的 db。

确保之后清理您的项目。

这是开始使用 Google 应用程序引擎时派上用场的小问题之一。您会发现自己将对象持久化到数据存储中,然后更改可持久化实体的 JDO 对象模型,最终得到过时的数据,这将使您的应用程序崩溃。

【讨论】:

  • dev_appserver.py 中有一个 -c 参数要从开发数据存储中删除。
  • @svrist 但这仅适用于 Python 应用程序引擎。有谁知道用Java做这件事的捷径吗? (与此同时,JohnIdol 的建议效果很好。)
  • 感谢@John:MAC OSX 中的确切路径在哪里?
  • Windows 中的路径在哪里?
  • @ShaneBest windows 中的路径类似于 ./target/yourappid-1.0-SNAPSHOT/WEB-INF/appengine-generated/local_db.bin
【解决方案2】:

最好的方法是 Nick 建议的远程 API 方法,他是来自 GoogleApp Engine 工程师,所以相信他。

做起来并不难,最新的 1.2.5 SDK 提供了现成的 remote_shell_api.py。所以去下载新的SDK。然后按照以下步骤操作:

  • 在命令行中连接远程服务器:remote_shell_api.py yourapp /remote_api shell 会询问你的登录信息,如果获得授权,它会为你创建一个 Python shell。您需要在 app.yaml 中为 /remote_api 设置 url 处理程序

  • 获取您要删除的实体,代码如下所示:

    from models import Entry
    query = Entry.all(keys_only=True)
    entries =query.fetch(1000)
    db.delete(entries)
    \# This could bulk delete 1000 entities a time

2013 年 10 月 28 日更新

  • remote_shell_api.py 已被remote_api_shell.py 取代,根据the documentation,您应该连接remote_api_shell.py -s your_app_id.appspot.com

  • 有一个新的实验性功能Datastore Admin,在应用设置中启用它后,您可以通过网络用户界面批量删除和备份您的数据存储。

【讨论】:

  • 其实你不需要fetch。只需 db.delete(Entry.all()) 即可。
  • 您需要在 500 个实体集中执行此操作,否则您会得到:BadRequestError: cannot delete more than 500 entity in a single call
  • 仅供参考,为了让您使用远程 api,您需要首先在您的应用程序中使用内置函数启用它:- remote_api: 在您的 YAML 文件中。更多信息在developers.google.com/appengine/articles/remote_api
  • 在调用 Entry.all() 时至少添加“keys_only=True”。如果您不需要检查数据,则无需获取整个条目。否则你只是在浪费计算周期。
  • +1 ... 但是:截至 2013 年,remote_shell_api.py 不存在。当前脚本名称是 remote_api_shell.py。另外,如果你使用 ndb(这是大多数人现在都在做的),推荐使用 ndb.delete_multi(model.Entry.query().fetch(keys_only=True))的方式
【解决方案3】:

在 Datastore 上处理批量删除的最快、最有效的方法是使用最新的 Google I/O 上宣布的新 mapper API

如果您选择的语言是Python,您只需在 mapreduce.yaml 文件中注册您的映射器并定义如下函数:

from mapreduce import operation as op
def process(entity):
 yield op.db.Delete(entity)

Java 上,您应该查看this article,它建议了这样的函数:

@Override
public void map(Key key, Entity value, Context context) {
    log.info("Adding key to deletion pool: " + key);
    DatastoreMutationPool mutationPool = this.getAppEngineContext(context)
            .getMutationPool();
    mutationPool.delete(value.getKey());
}

编辑:
从 SDK 1.3.8 开始,有一个 Datastore admin feature 用于此目的

【讨论】:

    【解决方案4】:

    运行服务器时可以clear the development server datastore

    /path/to/dev_appserver.py --clear_datastore=yes myapp

    您也可以将--clear_datastore 缩写为-c

    【讨论】:

    • 不确定这是否是最近的事情,但现在的实际语法是/path/to/google_appengine/dev_appserver.py --clear_datastore yes myappname/(注意“是”)
    • 这是在开发过程中重复删除数据存储的最有用的方法。随着选项很快过时,值得强调的是,这个标志在 2018 年 7 月仍然存在,并且适用于通过 gcloud CLI 安装的 dev_appserver
    • 在 270.0.0 版的 Google Cloud SDK 中,“--clear_datastore=yes”仍然可以使用等号
    【解决方案5】:

    如果您有大量数据,则需要使用脚本将其删除。不过,您可以使用 remote_api 以直接的方式从客户端清除数据存储区。

    【讨论】:

      【解决方案6】:

      在这里:转到 Datastore Admin,然后选择要删除的实体类型,然后单击删除。 Mapreduce 将负责删除!

      【讨论】:

        【解决方案7】:

        您可以使用多种方法从 App Engine 的数据存储区中删除条目:

        1. 首先,考虑您是否真的需要删除条目。这很昂贵,不移除它们可能会更便宜。

        2. 您可以使用数据存储区管理员手动删除所有条目。

        3. 您可以使用远程 API 并以交互方式删除条目。

        4. 您可以使用几行代码以编程方式删除条目。

        5. 您可以使用任务队列和游标批量删除它们。

        6. 或者您可以使用 Mapreduce 来获得更强大和更高级的东西。

        以下博客文章中解释了这些方法中的每一种: http://www.shiftedup.com/2015/03/28/how-to-bulk-delete-entries-in-app-engine-datastore

        希望对你有帮助!

        【讨论】:

          【解决方案8】:

          执行此操作的零设置方法是将执行任意代码 HTTP 请求发送到您正在运行的应用程序已经自动具有的管理服务:

          import urllib
          import urllib2
          
          urllib2.urlopen('http://localhost:8080/_ah/admin/interactive/execute',
              data = urllib.urlencode({'code' : 'from google.appengine.ext import db\n' +
                                                'db.delete(db.Query())'}))
          

          【讨论】:

          • 这仅适用于开发服务器。有生产等价物吗?
          【解决方案9】:

          来源

          我从http://code.google.com/appengine/articles/remote_api.html 得到这个。

          创建交互式控制台

          首先,您需要定义一个交互式 appendinge 控制台。因此,创建一个名为 appengine_console.py 的文件并输入:

          #!/usr/bin/python
          import code
          import getpass
          import sys
          
          # These are for my OSX installation. Change it to match your google_appengine paths. sys.path.append("/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine")
          sys.path.append("/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/yaml/lib")
          
          from google.appengine.ext.remote_api import remote_api_stub
          from google.appengine.ext import db
          
          def auth_func():
            return raw_input('Username:'), getpass.getpass('Password:')
          
          if len(sys.argv) < 2:
            print "Usage: %s app_id [host]" % (sys.argv[0],)
          app_id = sys.argv[1]
          if len(sys.argv) > 2:
            host = sys.argv[2]
          else:
            host = '%s.appspot.com' % app_id
          
          remote_api_stub.ConfigureRemoteDatastore(app_id, '/remote_api', auth_func, host)
          
          code.interact('App Engine interactive console for %s' % (app_id,), None, locals())
          



          创建 Mapper 基类

          一旦到位,创建这个 Mapper 类。我刚刚创建了一个名为 utils.py 的新文件并抛出了这个:

          class Mapper(object):
            # Subclasses should replace this with a model class (eg, model.Person).
            KIND = None
          
            # Subclasses can replace this with a list of (property, value) tuples to filter by.
            FILTERS = []
          
            def map(self, entity):
              """Updates a single entity.
          
              Implementers should return a tuple containing two iterables (to_update, to_delete).
              """
              return ([], [])
          
            def get_query(self):
              """Returns a query over the specified kind, with any appropriate filters applied."""
              q = self.KIND.all()
              for prop, value in self.FILTERS:
                q.filter("%s =" % prop, value)
              q.order("__key__")
              return q
          
            def run(self, batch_size=100):
              """Executes the map procedure over all matching entities."""
              q = self.get_query()
              entities = q.fetch(batch_size)
              while entities:
                to_put = []
                to_delete = []
                for entity in entities:
                  map_updates, map_deletes = self.map(entity)
                  to_put.extend(map_updates)
                  to_delete.extend(map_deletes)
                if to_put:
                  db.put(to_put)
                if to_delete:
                  db.delete(to_delete)
                q = self.get_query()
                q.filter("__key__ >", entities[-1].key())
                entities = q.fetch(batch_size)
          

          Mapper 应该只是一个抽象类,它允许您迭代给定类型的每个实体,无论是提取它们的数据,还是修改它们并将更新的实体存储回数据存储区。

          带着它跑!

          现在,启动您的 appengine 交互式控制台:

          $python appengine_console.py <app_id_here>
          

          这应该会启动交互式控制台。在其中创建模型的子类:

          from utils import Mapper
          # import your model class here 
          class MyModelDeleter(Mapper):
              KIND = <model_name_here>
          
              def map(self, entity):
                  return ([], [entity])
          

          最后,运行它(从您的交互式控制台): 映射器 = MyModelDeleter() mapper.run()

          就是这样!

          【讨论】:

            【解决方案10】:

            您可以使用网络界面进行操作。登录您的帐户,使用左侧的链接导航。在数据存储管理中,您可以选择修改和删除数据。使用相应的选项。

            【讨论】:

              【解决方案11】:

              我创建了一个插件面板,可用于您部署的 App Engine 应用程序。它在下拉列表中列出了数据存储中存在的种类,您可以单击一个按钮来安排“任务”,以删除特定种类的所有实体或简单的所有内容。你可以在这里下载:
              http://code.google.com/p/jobfeed/wiki/Nuke

              【讨论】:

                【解决方案12】:

                对于 Python,1.3.8 包含一个内置的实验性管理员。他们say:“在您的 app.yaml 文件中启用以下内置函数:”

                builtins:
                - datastore_admin: on
                

                “数据存储区删除目前仅适用于 Python 运行时。但是,Java 应用程序仍然可以通过创建一个在 app.yaml 中启用数据存储区管理的非默认 Python 应用程序版本来利用此功能。对 Java 的本机支持将包含在即将发布的版本中。”

                【讨论】:

                • 在 app.yaml 中添加配置报错。相反,我们可以从“管理”部分的“应用程序设置”页面启用它。有一个按钮可以启用它
                【解决方案13】:

                为您的应用打开“Datastore Admin”并启用 Admin。然后您的所有实体都将与复选框一起列出。您可以简单地选择不需要的实体并删除它们。

                【讨论】:

                  【解决方案14】:

                  这就是你要找的……

                  db.delete(Entry.all(keys_only=True))
                  

                  运行仅键查询比完全提取快得多,并且您的配额受到的影响较小,因为仅键查询被视为小型操作。

                  这是来自 Nick Johnson 的 link to an answer 进一步描述。

                  以下是用于截断表格的端到端 REST API 解决方案...

                  我设置了一个 REST API 来处理数据库事务,其中路由直接映射到正确的模型/操作。这可以通过输入正确的 url (example.com/inventory/truncate) 并登录来调用。

                  路线如下:

                  Route('/inventory/truncate', DataHandler, defaults={'_model':'Inventory', '_action':'truncate'})
                  

                  这是处理程序:

                  class DataHandler(webapp2.RequestHandler):
                    @basic_auth
                    def delete(self, **defaults):
                      model = defaults.get('_model')
                      action = defaults.get('_action')
                      module = __import__('api.models', fromlist=[model])
                      model_instance = getattr(module, model)()
                      result = getattr(model_instance, action)()
                  

                  它首先动态加载模型(即在 api.models 下找到的 Inventory),然后调用 action 参数中指定的正确方法 (Inventory.truncate())。

                  @basic_auth 是一个装饰器/包装器,它为敏感操作(即 POST/DELETE)提供身份验证。如果您担心安全问题,还可以使用oAuth decorator

                  最后调用action:

                  def truncate(self):
                    db.delete(Inventory.all(keys_only=True))
                  

                  看起来很神奇,但实际上非常简单。最好的部分是,delete() 可以通过向模型添加另一个操作来重新用于处理删除一个或多个结果。

                  【讨论】:

                    【解决方案15】:

                    您可以通过逐一删除所有种类来删除所有数据存储区。 与谷歌 appengine 仪表板。请按照以下步骤操作。

                    1. 登录https://console.cloud.google.com/datastore/settings
                    2. 单击打开数据存储区管理员。 (如果未启用,请启用它。)
                    3. 选择所有实体并按删除。(此步骤运行 map reduce 作业以删除所有选定的种类。)

                    更多信息请看这张图片http://storage.googleapis.com/bnifsc/Screenshot%20from%202015-01-31%2023%3A58%3A41.png

                    【讨论】:

                      【解决方案16】:

                      如果您有大量数据,使用网络界面可能会很耗时。 App Engine Launcher 实用程序可让您使用“启动时清除数据存储”复选框一次性删除所有内容。此实用程序现在可用于 Windows 和 Mac(Python 框架)。

                      【讨论】:

                        【解决方案17】:

                        对于开发服务器,您可以从终端运行它,而不是通过谷歌应用引擎启动器运行服务器:

                        dev_appserver.py --port=[端口号] --clear_datastore=yes [应用程序名称]

                        例如:我的应用程序“reader”在端口 15080 上运行。修改代码并重新启动服务器后,我只运行“dev_appserver.py --port=15080 --clear_datastore=yes reader”。

                        这对我有好处。

                        【讨论】:

                          【解决方案18】:

                          添加有关最近发展的答案。

                          Google 最近添加了数据存储区管理功能。您可以使用此控制台将实体备份、删除或复制到另一个应用程序。

                          https://developers.google.com/appengine/docs/adminconsole/datastoreadmin#Deleting_Entities_in_Bulk

                          【讨论】:

                            【解决方案19】:

                            我经常不想删除所有数据存储,因此我将 /war/WEB-INF/local_db.bin 的干净副本从源代码控制中提取出来。可能只是我,但似乎即使在开发模式停止的情况下,我也必须在拉取文件之前物理删除文件。这是在 Windows 上使用 Eclipse 的 subversion 插件。

                            【讨论】:

                              【解决方案20】:

                              PHP 变体:

                              import com.google.appengine.api.datastore.Query;
                              import com.google.appengine.api.datastore.DatastoreServiceFactory;
                              
                              define('DATASTORE_SERVICE', DatastoreServiceFactory::getDatastoreService());
                              
                              function get_all($kind) {
                                  $query = new Query($kind);
                                  $prepared = DATASTORE_SERVICE->prepare($query);
                                  return $prepared->asIterable();
                              }
                              
                              function delete_all($kind, $amount = 0) {
                                  if ($entities = get_all($kind)) {
                                      $r = $t = 0;
                                      $delete = array();
                                      foreach ($entities as $entity) {
                                          if ($r < 500) {
                                              $delete[] = $entity->getKey();
                                          } else {
                                              DATASTORE_SERVICE->delete($delete);
                                              $delete = array();
                                              $r = -1;
                                          }
                                          $r++; $t++;
                                          if ($amount && $amount < $t) break;
                                      }
                                      if ($delete) {
                                          DATASTORE_SERVICE->delete($delete);
                                      }
                                  }
                              }
                              

                              是的,这需要时间和 30 秒。是一个限制。我正在考虑将一个 ajax 应用示例自动化超过 30 秒。

                              【讨论】:

                              • 这甚至不是有效的 php。 import?将常量定义为对象实例?
                              【解决方案21】:
                              for amodel in db.Model.__subclasses__():
                                              dela=[]
                                              print amodel
                                              try:
                                                  m = amodel()
                                                  mq = m.all()
                                                  print mq.count()
                                                  for mw in mq:
                                                      dela.append(mw)
                                                  db.delete(dela)
                                          #~ print len(dela)
                              
                                              except:
                                                  pass
                              

                              【讨论】:

                                【解决方案22】:

                                如果您使用的是 ndb,对我来说清除数据存储区的方法:

                                ndb.delete_multi(ndb.Query(default_options=ndb.QueryOptions(keys_only=True)))
                                

                                【讨论】:

                                • 我认为这行不通。 Appengine 抱怨 Sorry, unexpected error: The kind "__Stat_Kind__" is reserved. 这似乎 appengine 有一些内部统计实体可以通过这种方法暴露(可能是他们的错误?)
                                【解决方案23】:

                                对于应用引擎上而非本地的任何数据存储,您可以使用new Datastore API。这里是a primer for how to get started

                                我编写了一个删除所有非内置实体的脚本。 API 变化非常快,因此作为参考,我在提交 990ab5c7f2063e8147bcc56ee222836fd3d6e15b 处克隆了它

                                from gcloud import datastore
                                from gcloud.datastore import SCOPE
                                from gcloud.datastore.connection import Connection
                                from gcloud.datastore import query
                                
                                from oauth2client import client
                                
                                def get_connection():
                                  client_email = 'XXXXXXXX@developer.gserviceaccount.com'
                                  private_key_string = open('/path/to/yourfile.p12', 'rb').read()
                                
                                  svc_account_credentials = client.SignedJwtAssertionCredentials(
                                    service_account_name=client_email,
                                    private_key=private_key_string,
                                    scope=SCOPE)
                                
                                  return Connection(credentials=svc_account_credentials)
                                
                                
                                def connect_to_dataset(dataset_id):
                                  connection = get_connection()
                                  datastore.set_default_connection(connection)
                                  datastore.set_default_dataset_id(dataset_id)
                                
                                if __name__ == "__main__":
                                  connect_to_dataset(DATASET_NAME)
                                  gae_entity_query = query.Query()
                                  gae_entity_query.keys_only()
                                  for entity in gae_entity_query.fetch():
                                    if entity.kind[0] != '_':
                                      print entity.kind
                                      entity.key.delete()
                                

                                【讨论】:

                                  【解决方案24】:
                                  • 延续 svpino 的理念,重用标记为删除的记录是明智之举。 (他的想法不是删除,而是标记为“已删除”未使用的记录)。一点点缓存/内存缓存来处理工作副本并仅将状态差异(所需任务之前和之后)写入数据存储区会使其变得更好。对于大型任务,可以将中间差异块写入数据存储,以避免在 memcache 消失时丢失数据。为了使其防丢失,可以检查 memcached 结果的完整性/存在性并重新启动任务(或所需部分)以重复丢失的计算。当数据差异写入数据存储时,所需的计算将被丢弃在队列中。

                                  • 其他类似于 map reduce 的想法是将实体种类分片到几个不同的实体种类,因此它将被收集在一起并作为单个实体种类对最终用户可见。条目仅标记为“已删除”。当每个分片的“已删除”条目数量超过某个限制时,“活动”条目将分布在其他分片之间,并且该分片将永远关闭,然后从开发控制台手动删除(猜测成本更低) upd:似乎没有下降控制台上的表,仅以正常价格逐条删除。

                                  • 可以通过查询大块记录来删除大量记录,而不会出现 gae 失败(至少在本地工作),并且有可能在时间结束后继续下一次尝试:

                                  
                                      qdelete.getFetchPlan().setFetchSize(100);
                                  
                                      while (true)
                                      {
                                          long result = qdelete.deletePersistentAll(candidates);
                                          LOG.log(Level.INFO, String.format("deleted: %d", result));
                                          if (result <= 0)
                                              break;
                                      }
                                  
                                  • 有时在主表中创建附加字段而不是将候选(相关记录)放入单独的表中也很有用。是的,字段可能是未索引/序列化的数组,计算成本很低。

                                  【讨论】:

                                    【解决方案25】:

                                    对于所有需要开发服务器快速解决方案的人(截至 2016 年 2 月撰写本文时):

                                    1. 停止开发服务器。
                                    2. 删除目标目录。
                                    3. 重建项目。

                                    这将擦除数据存储区中的所有数据。

                                    【讨论】:

                                      【解决方案26】:

                                      我对删除实时数据存储中的所有数据的现有解决方案感到非常沮丧,因此我创建了一个小型 GAE 应用程序,可以在 30 秒内删除相当多的数据。

                                      如何安装等:https://github.com/xamde/xydra

                                      【讨论】:

                                        【解决方案27】:

                                        对于java

                                        DatastoreService db = DatastoreServiceFactory.getDatastoreService();
                                        List<Key> keys = new ArrayList<Key>();
                                        for(Entity e : db.prepare(new Query().setKeysOnly()).asIterable())
                                            keys.add(e.getKey());
                                        db.delete(keys);
                                        

                                        在开发服务器中运行良好

                                        【讨论】:

                                          【解决方案28】:

                                          你有两种简单的方法,

                                          #1:为了节省成本,删除整个项目

                                          #2:使用 ts-datastore-orm:

                                          https://www.npmjs.com/package/ts-datastore-orm 等待 Entity.truncate(); 截断每秒可以删除大约 1K 行

                                          【讨论】:

                                            【解决方案29】:

                                            以下是我从香草Google Cloud Shell(无GAE)和python3天真地做到这一点的方法:

                                            from google.cloud import datastore
                                            client = datastore.Client()
                                            query.keys_only()
                                            for counter, entity in enumerate(query.fetch()):
                                                if entity.kind.startswith('_'):  # skip reserved kinds
                                                    continue
                                                print(f"{counter}: {entity.key}")
                                                client.delete(entity.key)
                                            

                                            即使密钥数量相对较少,这也需要很长时间,但它可以工作。

                                            有关 Python 客户端库的更多信息:https://googleapis.dev/python/datastore/latest/client.html

                                            【讨论】:

                                              猜你喜欢
                                              • 2010-11-03
                                              • 1970-01-01
                                              • 2014-05-13
                                              • 2011-02-16
                                              • 2013-12-03
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 1970-01-01
                                              相关资源
                                              最近更新 更多