删除Google App Engine中的所有数据

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

谷歌的正式答案是,你必须删除在多个请求分散的块。 您可以使用AJAX, 元刷新 ,或从脚本请求您的url,直到没有实体。

我目前正在通过键删除实体,而且似乎更快。

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 

从terminal,我运行curl -N http:// …

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

如果我是一个偏执的人,我想说谷歌应用程序引擎(GAE)如果我们想要移除数据,并不容易。 我将跳过关于索引大小的讨论,以及他们如何将6 GB的数据转换为35 GB的存储(按计费)。 这是另一个故事,但他们有办法解决这个问题 – 限制数量的属性来创build索引(自动生成索引)等等。

我决定写这篇文章的原因是我需要在沙盒里“核武”所有的种类。 我读了一下,最后提出了这个代码:

 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万条logging。 好多啊。 我不知道删除logging的成本是多less(也许更经济而不是删除它们)。 另一种方法是请求删除整个应用程序(沙箱)。 但是在大多数情况下这是不现实的。

我决定去更小的一组logging(容易查询)。 我知道我可以去500个实体,但是我开始接受非常高的失败率(重新删除function)。

来自GAE团队的请求:请添加一项function来删除单个事务中的所有实体。

尝试使用App Engine控制台,那么你甚至不需要部署任何特殊的代码

推测你的黑客是这样的:

 # 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)) 

正如你所说,如果有足够的数据,你将在获取所有logging之前打到请求超时。 您必须从外部多次重新调用此请求以确保所有数据都已被擦除; 容易做到,但很难理想。

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

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

我会从这里推断出,Google运行的原理是磁盘便宜,所以数据通常是孤立的(索引取代冗余数据),而不是删除。 由于目前每个应用程序都有固定的数据量(0.5 GB),对于非Google App Engine用户来说没有太大的帮助。

我已经尝试了db.delete(结果)和App Engine控制台,他们都没有为我工作。 从数据查看器手动删除条目(增加的限制高达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中包含redirect,而不是使用self.redirect。 我已经准备好在一夜之间摆脱桌子上的所有数据。 希望GAE团队能够让将来更容易丢表。

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

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

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

在Java上,你应该看看这篇文章 ,build议这样的function:

 @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()); } 

一个小费。 我build议你去了解remote_api这些types的用途(批量删除,修改等)。 但是,即使使用远程API,批量大小也可以一次限制在几百个。

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

用Django,设置url:

 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") 

如果你正在使用Java / JPA,你可以这样做:

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

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

是的,您可以:转到数据存储pipe理,然后select要删除的Entitiytypes,然后单击删除。 Mapreduce会照顾删除!

您可以使用任务队列来删除说100个对象的块。 在GAE中删除对象显示了GAE中pipe理function的有限性。 您必须在1000个实体或更less的实体上进行批处理。 您可以使用与csv一起使用的bulkloader工具,但文档不包含java。 我正在使用GAE Java,我的删除策略涉及2个servlet,一个用于实际删除,另一个用于加载任务队列。 当我想要做删除时,我运行队列加载servlet,它加载队列,然后GAE去执行队列中的所有任务。

怎么做:创build一个删除less量对象的servlet。 将servlet添加到您的任务队列。 回家或者做其他事情;)经常检查数据存储…

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

这对我工作:

 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) 

谢谢大家,我得到了我需要的东西。 :d
这可能是有用的,如果你有很多db模型删除,你可以在terminal发送它。 而且,您可以自己pipe理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) 

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

 dev_appserver.py --clear_datastore=yes . 

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

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

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

因为你在pipe理页面(… / _啊/pipe理员)与你想要删除的实体。