我想清除Google App Engine中特定类型的所有数据。是什么 最好的办法吗? 我写了一个删除脚本(hack),但因为有这么多数据 在几百条记录之后超时。
答案 0 :(得分:27)
我目前正在按键删除实体,而且似乎更快。
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:// ...
答案 1 :(得分:23)
您现在可以使用数据存储区管理员:https://developers.google.com/appengine/docs/adminconsole/datastoreadmin#Deleting_Entities_in_Bulk
答案 2 :(得分:10)
如果我是一个偏执狂的人,我会说谷歌应用引擎(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团队请求:请添加一项功能,以便在一次交易中删除所有类型的实体。
答案 3 :(得分:9)
尝试使用App Engine Console,您甚至不必部署任何特殊代码
答案 4 :(得分: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用户没什么帮助。
答案 5 :(得分:7)
我已经尝试过db.delete(结果)和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团队能够在将来更容易丢弃表格。
答案 6 :(得分:6)
来自Google的official answer是您必须在分布在多个请求中的块中删除。您可以使用AJAX,meta refresh或从脚本请求您的URL,直到没有实体为止。
答案 7 :(得分:5)
在数据存储上处理批量删除的最快捷有效的方法是使用最新mapper API上宣布的新Google I/O。
如果您选择的语言为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());
}
答案 8 :(得分:4)
一个提示。我建议您了解remote_api这些类型的用法(批量删除,修改等)。但是,即使使用远程api,批量大小也可以一次限制为几百个。
答案 9 :(得分:3)
不幸的是,没有办法轻松进行批量删除。最好的办法是编写一个脚本,每次调用删除合理数量的条目,然后重复调用它 - 例如,每当有更多数据要删除时,让删除脚本返回302重定向,然后使用“wget”获取它-max-redirect = 10000“(或其他一些大数字)。
答案 10 :(得分: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")
答案 11 :(得分:1)
在dev server上,可以cd到他的应用程序目录,然后像这样运行:
dev_appserver.py --clear_datastore=yes .
这样做会启动应用并清除数据存储区。如果您已经有另一个实例在运行,那么该应用程序将无法绑定到所需的IP,因此无法启动...并清除您的数据存储区。
答案 12 :(得分:1)
是的,您可以: 转到“数据存储管理”,然后选择要删除的实体类型,然后单击“删除”。 Mapreduce将负责删除!
答案 13 :(得分: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
答案 14 :(得分: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)
答案 15 :(得分: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)
答案 16 :(得分:0)
您可以使用任务队列删除100个对象的块。 删除GAE中的对象显示了管理员功能在GAE中的限制。您必须使用1000个或更少实体的批次。您可以使用与csv一起使用的bulkloader工具,但文档不包括java。 我正在使用GAE Java,我的删除策略涉及有2个servlet,一个用于实际删除,另一个用于加载任务队列。当我想要删除时,我运行队列加载servlet,它加载队列,然后GAE开始执行队列中的所有任务。
怎么做: 创建一个删除少量对象的servlet。 将servlet添加到任务队列。 回家或者做别的事情;) 经常检查数据存储区......
我有一个大约5000个对象的数据存储区,我每周清理一次,清理大约需要6个小时,所以我在周五晚上运行任务。 我使用相同的技术来批量加载我的数据,恰好是大约5000个对象,具有大约十几个属性。
答案 17 :(得分: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)
答案 18 :(得分:-2)
在javascript中,以下内容将删除页面上的所有条目:
document.getElementById("allkeys").checked=true;
checkAllEntities();
document.getElementById("delete_button").setAttribute("onclick","");
document.getElementById("delete_button").click();
鉴于您在管理页面(... / _ ah / admin)中有您要删除的实体。