Подтвердить что ты не робот

Удалите все данные в своем роде в Google App Engine

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

4b9b3361

Ответ 1

официальный ответ от Google заключается в том, что вам нужно удалить фрагменты, распределенные по нескольким запросам. Вы можете использовать AJAX, meta refresh или запросить свой URL-адрес от script, пока не осталось объектов.

Ответ 2

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

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://...

Ответ 4

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

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

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 объектов, но затем я начал получать очень высокие показатели отказа (функция удаления).

Мой запрос от команды GAE: добавьте функцию для удаления всех объектов в одной транзакции.

Ответ 5

Предположительно, ваш взлом был примерно таким:

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

Ответ 6

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

Ответ 7

Я пробовал db.delete(результаты) и App Engine Console, и никто из них, похоже, не работает для меня. Ручное удаление записей из Data Viewer (увеличенный лимит до 200) не сработало, так как я загрузил более 10000 записей. Я закончил писать этот script

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 упростит падение таблиц в будущем.

Ответ 8

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

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

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

В Java вы должны взглянуть на this статья, которая предлагает такую ​​функцию:

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

Ответ 9

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

Ответ 10

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

Ответ 11

С django, setup 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")

Ответ 13

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

Ответ 14

На сервере dev, можно подключиться к его каталогу приложений, а затем запустить его следующим образом:

dev_appserver.py --clear_datastore=yes .

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

Ответ 15

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

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

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

Ответ 16

Это сработало для меня:

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)

Ответ 17

Спасибо всем, ребята, я получил то, что мне нужно.: D
Это может быть полезно, если у вас есть много моделей db для удаления, вы можете отправить их в свой терминал. А также вы можете управлять списком удаления в 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

И, конечно, вы должны сопоставить ссылку с моделью в файле (например, 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)

Ответ 18

Чтобы удалить все сущности данного вида в 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)

Ответ 19

В javascript следующие элементы будут удалены на странице:

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

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