world standard hello google for flexible engine docs app python google-app-engine

python - standard - google cloud sdk app engine



Eliminar todos los datos de un tipo en Google App Engine (18)

Me gustaría eliminar todos los datos de un tipo específico en Google App Engine. ¿Cuál es la mejor manera de hacer esto? Escribí un script de eliminación (hack), pero dado que hay tanta información, se agota el tiempo de espera después de unos cientos de registros.


Actualmente estoy borrando las entidades por su clave, y parece ser más rápido.

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

desde la terminal, ejecuto curl -N http: // ...



Con django, url de configuración:

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

Vista de configuración

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

Luego ejecuta en powershell:

$client = new-object System.Net.WebClient $client.DownloadString("http://your-app.com/Model/bdelete/?limit=400")


Desafortunadamente, no hay forma de hacer una eliminación masiva fácilmente. Su mejor opción es escribir un script que elimine un número razonable de entradas por invocación y luego llamarlo repetidamente, por ejemplo, haciendo que su script de eliminación devuelva un redireccionamiento 302 cada vez que haya más datos para eliminar, y luego ir a buscarlo con "wget- -max-redirect = 10000 "(o algún otro gran número).


En javascript, lo siguiente eliminará todas las entradas en la página:

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

dado que se encuentra en la página de administración (... / _ ah / admin) con las entidades que desea eliminar.


En un servidor de desarrollo , uno puede cd al directorio de su aplicación y luego ejecutarlo así:

dev_appserver.py --clear_datastore=yes .

Al hacerlo, se iniciará la aplicación y se borrará el almacén de datos. Si ya tiene otra instancia ejecutándose, la aplicación no podrá unirse a la IP necesaria y, por lo tanto, no podrá iniciarse ... y borrar su almacén de datos.


Es de suponer que tu truco fue algo como esto:

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

Como dices, si hay datos suficientes, alcanzarás el tiempo de espera de solicitud antes de que supere todos los registros. Tendría que volver a invocar esta solicitud varias veces desde el exterior para asegurarse de que se borraron todos los datos; lo suficientemente fácil de hacer, pero apenas ideal.

La consola de administración no parece ofrecer ninguna ayuda, ya que (a partir de mi propia experiencia con ella), parece que solo permite que se enumeren las entidades de un tipo determinado y luego se eliminan página por página.

Al realizar pruebas, tuve que purgar mi base de datos al inicio para deshacerme de los datos existentes.

De esto deduciría que Google opera bajo el principio de que el disco es barato, por lo que los datos suelen quedar huérfanos (en lugar de eliminarse los índices de datos redundantes). Dado que actualmente hay una cantidad fija de datos disponible para cada aplicación (0.5 GB), no es de mucha ayuda para los usuarios que no son de Google App Engine.


Esto funcionó para mí:

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)


Gracias a todos, obtuve lo que necesito. :RE
Esto puede ser útil si tiene muchos modelos de DB para eliminar, puede enviarlo a su terminal. Y también, puede administrar la lista de eliminación en DB_MODEL_LIST usted mismo.
Eliminar DB_1:

python bulkdel.py 10 DB_1

Eliminar todos los DB:

python bulkdel.py 11

Aquí está el archivo 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 )

Y aquí está la versión modificada del código de 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

Y, por supuesto, debe asignar el enlace al modelo en un archivo (como main.py en GAE),;)
En caso de que algunos tipos como yo lo necesitemos en detalle, aquí es parte de 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)


Intenté db.delete (resultados) y App Engine Console, y ninguno de ellos parece funcionar para mí. La eliminación manual de entradas del Visor de datos (límite aumentado hasta 200) tampoco funcionó, ya que he cargado más de 10000 entradas. Terminé de escribir este 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)

El truco consistía en incluir la redirección en html en lugar de usar self.redirect. Estoy listo para esperar toda la noche para deshacerme de todos los datos en mi mesa. Con suerte, el equipo de GAE hará que sea más fácil dejar caer tablas en el futuro.


Intenta usar App Engine Console, entonces ni siquiera tienes que implementar ningún código especial


La respuesta oficial de Google es que debe eliminar en fragmentos distribuidos en múltiples solicitudes. Puede usar AJAX, meta refresh o solicitar su URL desde un script hasta que no queden otras entidades.


La forma más rápida y eficiente de manejar la eliminación masiva en Datastore es mediante el uso de la nueva API de correlación anunciada en el último Google I / O.

Si su idioma de elección es Python , solo tiene que registrar su mapper en un archivo mapreduce.yaml y definir una función como esta:

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

En Java deberías echar un vistazo a este artículo que sugiere una función como esta:

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


Puede usar las colas de tareas para borrar fragmentos de, digamos, 100 objetos. Eliminar objetos en GAE muestra cuán limitadas son las capacidades de Admin en GAE. Tienes que trabajar con lotes en 1000 entidades o menos. Puede usar la herramienta de carga masiva que funciona con CSV, pero la documentación no cubre Java. Estoy usando GAE Java y mi estrategia para eliminaciones implica tener 2 servlets, uno para eliminar realmente y otro para cargar las colas de tareas. Cuando quiero hacer una eliminación, ejecuto el servlet de carga de la cola, carga las colas y luego GAE va a trabajar ejecutando todas las tareas en la cola.

Cómo hacerlo: crea un servlet que elimine una pequeña cantidad de objetos. Agregue el servlet a sus colas de tareas. Vete a casa o trabaja en otra cosa;) Mira el almacén de datos de vez en cuando ...

Tengo un almacén de datos con alrededor de 5000 objetos que purgo todas las semanas y me lleva unas 6 horas limpiarlo, así que ejecuto la tarea el viernes a la noche. Utilizo la misma técnica para cargar mis datos a granel, que son aproximadamente 5000 objetos, con aproximadamente una docena de propiedades.


Sí, puede: vaya a Administrador de Datastore, y luego seleccione el tipo de entidad que desea eliminar y haga clic en Eliminar. ¡Mapreduce se encargará de eliminar!



Si fuera una persona paranoica, diría que Google App Engine (GAE) no nos ha facilitado la eliminación de datos si queremos. Voy a omitir el debate sobre los tamaños de índice y cómo se traducen los 6 GB de datos a 35 GB de almacenamiento (que se facturarán). Esa es otra historia, pero tienen formas de evitarlo: limitar el número de propiedades para crear índices (índices generados automáticamente), etcétera.

La razón por la que decidí escribir esta publicación es que necesito "nuclear" todas mis clases en una caja de arena. Lo leí y finalmente se me ocurrió este código:

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

Tengo más de 6 millones de registros. Eso es mucho. No tengo idea de cuál será el costo de borrar los registros (quizás sea más económico no eliminarlos). Otra alternativa sería solicitar una eliminación para toda la aplicación (sandbox). Pero eso no es realista en la mayoría de los casos.

Decidí ir con grupos más pequeños de registros (en consulta fácil). Sé que podría ir a 500 entidades, pero luego comencé a recibir tasas muy altas de fallas (función de borrar de nuevo).

Mi solicitud al equipo de GAE: agregue una función para eliminar todas las entidades de un tipo en una sola transacción.


Un consejo. Sugiero que conozcas remote_api para este tipo de usos (eliminación masiva, modificación, etc.). Pero, incluso con la API remota, el tamaño del lote puede limitarse a unos pocos cientos a la vez.