45

我想清除 Google App Engine 中特定类型的所有数据。做这个的最好方式是什么?我写了一个删除脚本(hack),但是由于有这么多数据,几百条记录后超时。

4

19 回答 19

28

我目前正在通过它们的键删除实体,它似乎更快。

from google.appengine.ext import db

class bulkdelete(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        try:
            while True:
                q = db.GqlQuery("SELECT __key__ FROM MyModel")
                assert q.count()
                db.delete(q.fetch(200))
                time.sleep(0.5)
        except Exception, e:
            self.response.out.write(repr(e)+'\n')
            pass

从终端,我运行 curl -N http://...

于 2009-06-21T11:41:24.207 回答
23

您现在可以为此使用数据存储区管理员:https ://developers.google.com/appengine/docs/adminconsole/datastoreadmin#Deleting_Entities_in_Bulk

于 2011-09-18T21:17:52.863 回答
10

如果我是一个偏执的人,我会说 Google App Engine (GAE) 并没有让我们轻松地删除数据,如果我们愿意的话。我将跳过关于索引大小以及它们如何将 6 GB 数据转换为 35 GB 存储(收费)的讨论。那是另一个故事,但他们确实有办法解决这个问题 - 限制属性数量以在(自动生成的索引)等上创建索引。

我决定写这篇文章的原因是我需要在沙箱中“核对”我所有的种类。我读了它,最后想出了这个代码:

package com.intillium.formshnuker;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;

import com.google.appengine.api.labs.taskqueue.QueueFactory;
import com.google.appengine.api.labs.taskqueue.TaskOptions.Method;

import static com.google.appengine.api.labs.taskqueue.TaskOptions.Builder.url;

@SuppressWarnings("serial")
public class FormsnukerServlet extends HttpServlet {

 public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException {

  response.setContentType("text/plain");

  final String kind = request.getParameter("kind");
  final String passcode = request.getParameter("passcode");

  if (kind == null) {
   throw new NullPointerException();
  }

  if (passcode == null) {
   throw new NullPointerException();
  }

  if (!passcode.equals("LONGSECRETCODE")) {
   response.getWriter().println("BAD PASSCODE!");
   return;
  }

  System.err.println("*** deleting entities form " + kind);

  final long start = System.currentTimeMillis();

  int deleted_count = 0;
  boolean is_finished = false;

  final DatastoreService dss = DatastoreServiceFactory.getDatastoreService();

  while (System.currentTimeMillis() - start < 16384) {

   final Query query = new Query(kind);

   query.setKeysOnly();

   final ArrayList<Key> keys = new ArrayList<Key>();

   for (final Entity entity: dss.prepare(query).asIterable(FetchOptions.Builder.withLimit(128))) {
    keys.add(entity.getKey());
   }

   keys.trimToSize();

   if (keys.size() == 0) {
    is_finished = true;
    break;
   }

   while (System.currentTimeMillis() - start < 16384) {

    try {

     dss.delete(keys);

     deleted_count += keys.size();

     break;

    } catch (Throwable ignore) {

     continue;

    }

   }

  }

  System.err.println("*** deleted " + deleted_count + " entities form " + kind);

  if (is_finished) {

   System.err.println("*** deletion job for " + kind + " is completed.");

  } else {

   final int taskcount;

   final String tcs = request.getParameter("taskcount");

   if (tcs == null) {
    taskcount = 0;
   } else {
    taskcount = Integer.parseInt(tcs) + 1;
   }

   QueueFactory.getDefaultQueue().add(
    url("/formsnuker?kind=" + kind + "&passcode=LONGSECRETCODE&taskcount=" + taskcount).method(Method.GET));

   System.err.println("*** deletion task # " + taskcount + " for " + kind + " is queued.");

  }

  response.getWriter().println("OK");

 }

}

我有超过 600 万条记录。好多啊。我不知道删除记录的成本是多少(不删除它们可能更经济)。另一种选择是请求删除整个应用程序(沙盒)。但这在大多数情况下是不现实的。

我决定使用较小的记录组(便于查询)。我知道我可以选择 500 个实体,但后来我开始收到非常高的失败率(重新删除功能)。

我对 GAE 团队的要求:请添加一个功能以在单个事务中删除一种类型的所有实体。

于 2009-12-10T17:41:07.043 回答
9

大概你的黑客是这样的:

# Deleting all messages older than "earliest_date"
q = db.GqlQuery("SELECT * FROM Message WHERE create_date < :1", earliest_date)
results = q.fetch(1000)

while results:
    db.delete(results)
    results = q.fetch(1000, len(results))

正如您所说,如果有足够的数据,您将在它通过所有记录之前达到请求超时。您必须从外部多次重新调用此请求,以确保删除所有数据;很容易做到,但并不理想。

管理控制台似乎没有提供任何帮助,因为(根据我自己的经验),它似乎只允许列出给定类型的实体,然后逐页删除。

在测试时,我不得不在启动时清除我的数据库以摆脱现有数据。

我会由此推断,谷歌的运作原则是磁盘便宜,因此数据通常是孤立的(冗余数据的索引被替换),而不是被删除。鉴于目前每个应用程序可用的数据量是固定的(0.5 GB),这对非 Google App Engine 用户没有多大帮助。

于 2008-09-20T18:34:42.200 回答
9

尝试使用App Engine 控制台,然后您甚至不必部署任何特殊代码

于 2008-11-14T23:58:35.940 回答
7

我已经尝试过 db.delete(results) 和 App Engine Console,但它们似乎都不适合我。从数据查看器中手动删除条目(将限制增加到 200 个)也不起作用,因为我已经上传了超过 10000 个条目。我写完了这个脚本

from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
import wsgiref.handlers
from mainPage import YourData #replace this with your data
class CleanTable(webapp.RequestHandler):
    def get(self, param):
        txt = self.request.get('table')
        q = db.GqlQuery("SELECT * FROM "+txt)
        results = q.fetch(10)
        self.response.headers['Content-Type'] = 'text/plain'
        #replace yourapp and YouData your app info below.
        self.response.out.write("""
          <html>
          <meta HTTP-EQUIV="REFRESH" content="5; url=http://yourapp.appspot.com/cleanTable?table=YourData">
            <body>""")

        try:
            for i in range(10):
                db.delete(results)
                results = q.fetch(10, len(results))
                self.response.out.write("<p>10 removed</p>")
                self.response.out.write("""
                </body>
              </html>""")

        except Exception, ints:
            self.response.out.write(str(inst))

def main():
  application = webapp.WSGIApplication([
    ('/cleanTable(.*)', CleanTable),
  ])

  wsgiref.handlers.CGIHandler().run(application)  

诀窍是在 html 中包含重定向,而不是使用 self.redirect。我已经准备好等待一夜以摆脱我表中的所有数据。希望 GAE 团队将来可以更轻松地删除表格。

于 2008-11-27T06:00:44.893 回答
6

谷歌的官方回答是你必须在多个请求中分块删除。您可以使用 AJAX、meta refresh或从脚本请求您的 URL,直到没有实体为止。

于 2008-09-23T02:44:10.277 回答
5

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

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

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

Java上,你应该看看这篇文章,它建议了一个这样的函数:

@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());
}
于 2010-09-08T20:49:35.323 回答
4

一个提示。我建议您了解这些类型的使用(批量删除,修改等)的remote_api 。但是,即使使用远程 API,批量大小也可以限制为一次几百个。

于 2009-09-09T15:47:34.510 回答
3

不幸的是,没有办法轻松地进行批量删除。最好的办法是编写一个脚本,在每次调用时删除合理数量的条目,然后重复调用它——例如,只要有更多数据要删除,让你的删除脚本返回 302 重定向,然后使用“wget - -max-redirect=10000"(或其他一些较大的数字)。

于 2008-09-20T19:03:04.800 回答
1

使用 django,设置网址:

url(r'^Model/bdelete/$', v.bulk_delete_models, {'model':'ModelKind'}),

设置视图

def bulk_delete_models(request, model):
    import time
    limit = request.GET['limit'] or 200
    start = time.clock()
    set = db.GqlQuery("SELECT __key__ FROM %s" % model).fetch(int(limit))
    count = len(set)
    db.delete(set)
    return HttpResponse("Deleted %s %s in %s" % (count,model,(time.clock() - start)))

然后在powershell中运行:

$client = new-object System.Net.WebClient
$client.DownloadString("http://your-app.com/Model/bdelete/?limit=400")
于 2010-03-24T21:12:14.317 回答
1

如果您使用的是 Java/JPA,则可以执行以下操作:

    em = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory)
    Query q = em.createQuery("delete from Table t");
    int number = q.executeUpdate();

Java/JDO 信息可以在这里找到:http ://code.google.com/appengine/docs/java/datastore/queriesandindexes.html#Delete_By_Query

于 2011-01-05T03:12:37.013 回答
1

是的,您可以:转到 Datastore Admin,然后选择要删除的实体类型,然后单击删除。Mapreduce 将负责删除!

于 2011-12-09T11:42:36.640 回答
1

开发服务器上,可以 cd 到他的应用程序目录,然后像这样运行它:

dev_appserver.py --clear_datastore=yes .

这样做将启动应用程序并清除数据存储区。如果您已经有另一个实例正在运行,则该应用程序将无法绑定到所需的 IP,因此无法启动......并清除您的数据存储。

于 2015-11-27T20:11:34.680 回答
0

您可以使用任务队列来删除 100 个对象的块。在 GAE 中删除对象显示了 GAE 中管理功能的局限性。您必须处理 1000 个或更少实体的批次。您可以使用适用于 csv 的 bulkloader 工具,但文档不包括 java。我正在使用 GAE Java,我的删除策略包括 2 个 servlet,一个用于实际删除,另一个用于加载任务队列。当我想删除时,我运行队列加载 servlet,它加载队列,然后 GAE 开始执行队列中的所有任务。

怎么做:创建一个删除少量对象的servlet。将 servlet 添加到您的任务队列中。回家或从事其他工作;)每隔一段时间检查一次数据存储...

我有一个包含大约 5000 个对象的数据存储,我每周都会清除这些对象,清理大约需要 6 个小时,所以我在星期五晚上运行该任务。我使用相同的技术批量加载我的数据,这些数据恰好是大约 5000 个对象,大约有十几个属性。

于 2010-02-11T14:48:22.167 回答
0

这对我有用:

class ClearHandler(webapp.RequestHandler):  
    def get(self):  
        self.response.headers['Content-Type'] = 'text/plain'  
        q = db.GqlQuery("SELECT * FROM SomeModel")  
        self.response.out.write("deleting...")  
        db.delete(q)
于 2010-07-31T01:41:22.473 回答
0

谢谢大家,我得到了我需要的东西。:D
如果您有很多数据库模型要删除,这可能很有用,您可以在终端中发送它。此外,您可以自己管理 DB_MODEL_LIST 中的删除列表。
删除 DB_1:

python bulkdel.py 10 DB_1

删除所有数据库:

python bulkdel.py 11

这是 bulkdel.py 文件:

import sys, os

URL = 'http://localhost:8080'
DB_MODEL_LIST = ['DB_1', 'DB_2', 'DB_3']

# Delete Model
if sys.argv[1] == '10' :
    command = 'curl %s/clear_db?model=%s' % ( URL, sys.argv[2] )
    os.system( command )

# Delete All DB Models
if sys.argv[1] == '11' :
    for model in DB_MODEL_LIST :
        command = 'curl %s/clear_db?model=%s' % ( URL, model )
        os.system( command )

这是 alexandre fiori 代码的修改版本。

from google.appengine.ext import db
class DBDelete( webapp.RequestHandler ):
    def get( self ):
        self.response.headers['Content-Type'] = 'text/plain'
        db_model = self.request.get('model')
        sql = 'SELECT __key__ FROM %s' % db_model

        try:
            while True:
                q = db.GqlQuery( sql )
                assert q.count()
                db.delete( q.fetch(200) )
                time.sleep(0.5)
        except Exception, e:
            self.response.out.write( repr(e)+'\n' )
            pass

当然,您应该将链接映射到文件中的模型(如 GAE 中的 main.py),;)
如果像我这样的人需要它的详细信息,这里是 main.py 的一部分:

from google.appengine.ext import webapp
import utility # DBDelete was defined in utility.py
application = webapp.WSGIApplication([('/clear_db',utility.DBDelete ),('/',views.MainPage )],debug = True)
于 2011-09-03T07:27:45.373 回答
0

要在 Google App Engine 中删除给定种类中的所有实体,您只需执行以下操作:

from google.cloud import datastore

query = datastore.Client().query(kind = <KIND>)
results = query.fetch()
for result in results:
    datastore.Client().delete(result.key)
于 2019-02-06T12:15:29.463 回答
-2

在 javascript 中,以下内容将删除页面上的所有条目:

document.getElementById("allkeys").checked=true;
checkAllEntities();
document.getElementById("delete_button").setAttribute("onclick","");
document.getElementById("delete_button").click();

假设您在要删除的实体的管理页面 (.../_ah/admin) 上。

于 2012-11-29T13:06:19.137 回答