Вопрос по python – Удалить все данные для вида в Google App Engine

44

Я хотел бы стереть все данные для определенного вида в Google App Engine. Что лучший способ сделать это? Я написал сценарий удаления (взломать), но так как есть так много данных истекло время ожидания после нескольких сотен записей.

это боль в шее user784435

Ваш Ответ

19   ответов
10

Если бы я был параноиком, я бы сказал, что Google App Engine (GAE) не позволил нам легко удалить данные, если мы этого захотим. Я собираюсь пропустить обсуждение размеров индекса и того, как они переводят 6 ГБ данных в 35 ГБ хранилища (счет выставлен). Это другая история, но у них есть способы обойти это - ограничить количество свойств для создания индекса (автоматически сгенерированных индексов) и так далее.

Причина, по которой я решил написать этот пост, заключается в том, что мне нужно "nuke" все мои виды в песочнице. Я прочитал об этом и, наконец, придумал этот код:

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

 }

}

У меня более 6 миллионов записей. Это много. Я понятия не имею, сколько будет стоить удаление записей (может быть, более экономичным, чтобы не удалять их). Другой вариант - запросить удаление для всего приложения (песочница). Но это нереально в большинстве случаев.

Я решил пойти с небольшими группами записей (в простой запрос). Я знаю, что могу пойти на 500 объектов, но потом я начал получать очень высокие показатели отказов (функция повторного удаления).

My request from GAE team: please add a feature to delete all entities of a kind in a single transaction.

1

Да, ты можешь: Перейдите в Datastore Admin, затем выберите тип Entitiy, который вы хотите удалить, и нажмите «Удалить». Mapreduce позаботится об удалении!

23

Теперь вы можете использовать администратора хранилища данных для этого:https://developers.google.com/appengine/docs/adminconsole/datastoreadmin#Deleting_Entities_in_Bulk

Error: User Rate Limit Exceededmarram.posterous.com/…
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
-2

В javascript следующее удалит все записи для на странице:

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

учитывая, что вы находитесь на странице администратора (... / _ ah / admin) с сущностями, которые хотите удалить.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
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: // ...

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
6

официальный ответ от Google заключается в том, что вы должны удалять кусками, распределенными по нескольким запросам. Вы можете использовать AJAX,метаобновлениеили запросите ваш URL из скрипта, пока не останется никаких сущностей.

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 )

А вот модифицированная версия кода Александра Фьори.

from google.appengine.ext import db
class DBDelete( webapp.RequestHandler ):
    def get( self ):
        self.response.headers['Content-Type'] = 'text/pla,in'
        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

И, конечно, вы должны отобразить ссылку на модель в файле (например, main.py в GAE),;)
В случае, если некоторые парни, как я, нуждаются в этом подробно, вот часть 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)
5

Самый быстрый и эффективный способ массового удаления в Datastore - использование новогоAPI картографа объявлено о последнихGoogle I / O.

Если ваш язык выборапитонВы просто должны зарегистрировать свой картограф вmapreduce.yaml файл и определите функцию следующим образом:

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

НаДжава Вы должны взглянуть наЭта статья это предполагает такую функцию:

@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());
}
Error: User Rate Limit Exceeded
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))

Как вы говорите, если данных достаточно, вы достигнете тайм-аута запроса, прежде чем он пройдет через все записи. Вы должны повторно вызывать этот запрос несколько раз извне, чтобы убедиться, что все данные были стерты; достаточно легко сделать, но вряд ли идеально.

Похоже, что консоль администратора не предлагает никакой помощи, поскольку (исходя из моего собственного опыта работы с ней) она, по-видимому, позволяет только перечислять сущности определенного типа, а затем удалять постранично.

При тестировании мне приходилось очищать базу данных при запуске, чтобы избавиться от существующих данных.

Из этого я могу сделать вывод, что Google работает по принципу, что диск дешев, и поэтому данные, как правило, теряются (индексы заменяются избыточными данными), а не удаляются. Учитывая, что в настоящее время каждому приложению доступно фиксированное количество данных (0,5 ГБ), это не очень помогает пользователям, не использующим Google App Engine.

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

Насервер разработкиможно перейти в каталог своего приложения и запустить его так:

dev_appserver.py --clear_datastore=yes .

Это запустит приложение и очистит хранилище данных. Если у вас уже запущен другой экземпляр, приложение не сможет привязаться к нужному IP-адресу и, следовательно, не сможет запуститься ... и очистить ваше хранилище данных.

7

Я пробовал db.delete (результаты) и консоль App Engine, но ни один из них мне не подходит. Удаление записей из Data Viewer вручную (увеличение лимита до 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 упростит отбрасывание таблиц в будущем.

Error: User Rate Limit ExceededdateError: User Rate Limit ExceededDateError: User Rate Limit ExceededinstError: User Rate Limit ExceededintsError: User Rate Limit ExceededtxtError: User Rate Limit Exceeded5Error: User Rate Limit ExceededforError: User Rate Limit Exceededwhile db.delete(results):Error: User Rate Limit ExceededbreakError: User Rate Limit ExceededexceptError: User Rate Limit Exceeded
0

Вы можете использовать очереди задач для удаления фрагментов, скажем, из 100 объектов. Удаление объектов в GAE показывает, насколько ограничены возможности администратора в GAE. Вы должны работать с партиями на 1000 объектов или менее. Вы можете использовать инструмент массового загрузчика, который работает с CSV, но документация не распространяется на Java. Я использую GAE Java, и моя стратегия удаления состоит из двух сервлетов: один для фактического удаления, а другой для загрузки очередей задач. Когда я хочу сделать удаление, я запускаю сервлет загрузки очереди, он загружает очереди, а затем GAE переходит к работе, выполняя все задачи в очереди.

Как это сделать: Создайте сервлет, который удаляет небольшое количество объектов. Добавьте сервлет в ваши очереди задач. Иди домой или поработай над чем-то другим;) Проверяйте хранилище данных так часто ...

У меня есть хранилище данных с около 5000 объектов, которые я удаляю каждую неделю, и на очистку уходит около 6 часов, поэтому я запускаю задачу в пятницу вечером. Я использую ту же технику для массовой загрузки моих данных, которая насчитывает около 5000 объектов с примерно дюжиной свойств.

4

Один совет Я предлагаю вам узнатьremote_api для этих типов использования (массовое удаление, изменение и т. д.). Но даже с удаленным API размер партии может быть ограничен несколькими сотнями за раз.

Error: User Rate Limit Exceeded
1

С помощью 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")
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

9

Попробуйте использоватьКонсоль App Engine тогда вам даже не придется развертывать какой-либо специальный код

Error: User Rate Limit Exceeded
3

К сожалению, нет способа легко выполнить массовое удаление. Лучше всего написать сценарий, который удаляет разумное количество записей на один вызов, а затем повторно вызывать его - например, если ваш сценарий удаления возвращает перенаправление 302 всякий раз, когда есть еще данные для удаления, а затем извлекает его с помощью & quot ; wget --max-redirect = 10000 & quot; (или другое большое количество).

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
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)

Похожие вопросы