google-app-engine - features - google app engine flex vs standard
¿Cómo eliminar todo el almacén de datos en Google App Engine? (27)
¿Alguien sabe cómo eliminar todo el almacén de datos en Google App Engine ?
Fuente
Crear la consola interactiva
Primero, necesita definir una consola de appenginge interactiva. Por lo tanto, cree un archivo llamado appengine_console.py e ingrese esto:
#!/usr/bin/python
import code
import getpass
import sys
# These are for my OSX installation. Change it to match your google_appengine paths. sys.path.append("/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine")
sys.path.append("/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/yaml/lib")
from google.appengine.ext.remote_api import remote_api_stub
from google.appengine.ext import db
def auth_func():
return raw_input(''Username:''), getpass.getpass(''Password:'')
if len(sys.argv) < 2:
print "Usage: %s app_id [host]" % (sys.argv[0],)
app_id = sys.argv[1]
if len(sys.argv) > 2:
host = sys.argv[2]
else:
host = ''%s.appspot.com'' % app_id
remote_api_stub.ConfigureRemoteDatastore(app_id, ''/remote_api'', auth_func, host)
code.interact(''App Engine interactive console for %s'' % (app_id,), None, locals())
Crear la clase base de Mapper
Una vez que esté en su lugar, crea esta clase de Mapper. Acabo de crear un nuevo archivo llamado utils.py y lancé esto:
class Mapper(object):
# Subclasses should replace this with a model class (eg, model.Person).
KIND = None
# Subclasses can replace this with a list of (property, value) tuples to filter by.
FILTERS = []
def map(self, entity):
"""Updates a single entity.
Implementers should return a tuple containing two iterables (to_update, to_delete).
"""
return ([], [])
def get_query(self):
"""Returns a query over the specified kind, with any appropriate filters applied."""
q = self.KIND.all()
for prop, value in self.FILTERS:
q.filter("%s =" % prop, value)
q.order("__key__")
return q
def run(self, batch_size=100):
"""Executes the map procedure over all matching entities."""
q = self.get_query()
entities = q.fetch(batch_size)
while entities:
to_put = []
to_delete = []
for entity in entities:
map_updates, map_deletes = self.map(entity)
to_put.extend(map_updates)
to_delete.extend(map_deletes)
if to_put:
db.put(to_put)
if to_delete:
db.delete(to_delete)
q = self.get_query()
q.filter("__key__ >", entities[-1].key())
entities = q.fetch(batch_size)
Se supone que Mapper es solo una clase abstracta que le permite iterar sobre cada entidad de un tipo dado, ya sea para extraer sus datos o para modificarlos y almacenar las entidades actualizadas en el almacén de datos.
¡Corre con eso!
Ahora, inicie su consola interactiva appengine:
$python appengine_console.py <app_id_here>
Eso debería comenzar la consola interactiva. En él crea una subclase de Modelo:
from utils import Mapper
# import your model class here
class MyModelDeleter(Mapper):
KIND = <model_name_here>
def map(self, entity):
return ([], [entity])
Y, finalmente, ejecútelo (desde su consola interactiva): mapper = MyModelDeleter () mapper.run ()
¡Eso es!
A menudo no quiero borrar todo el almacén de datos, así que saco una copia limpia del control de fuente /war/WEB-INF/local_db.bin out. Puede que sea solo yo, pero parece que incluso con el Modo Dev parado, tengo que eliminar físicamente el archivo antes de tirarlo. Esto está en Windows usando el complemento de subversión para Eclipse.
Abra "Datastore Admin" para su aplicación y habilite Admin. Luego, todas sus entidades aparecerán en la lista con casillas de verificación. Simplemente puede seleccionar las entidades no deseadas y eliminarlas.
Agregando respuesta sobre desarrollos recientes.
Google agregó recientemente la función de administración del almacén de datos. Puede hacer una copia de seguridad, eliminar o copiar sus entidades a otra aplicación usando esta consola.
https://developers.google.com/appengine/docs/adminconsole/datastoreadmin#Deleting_Entities_in_Bulk
Aquí tienes: ve al administrador de Datastore, y luego selecciona el tipo de entidad que deseas eliminar y haz clic en Eliminar. ¡Mapreduce se encargará de eliminar!
Creé un panel de complementos que se puede usar con las aplicaciones implementadas de App Engine. Enumera los tipos que están presentes en el almacén de datos en un menú desplegable, y puede hacer clic en un botón para programar "tareas" que eliminan todas las entidades de un tipo específico o simplemente todo. Puedes descargarlo aquí:
http://code.google.com/p/jobfeed/wiki/Nuke
El mejor enfoque es el método API remoto sugerido por Nick, es ingeniero de App Engine de Google , así que confía en él.
No es tan difícil de hacer, y el último 1.2.5 SDK proporciona el remote_shell_api.py fuera de la plataforma. Así que ve a descargar el nuevo SDK. Luego sigue los pasos:
conecte el servidor remoto en su línea de comando:
remote_shell_api.py yourapp /remote_api
El shell le pedirá su información de inicio de sesión y, si está autorizado, creará un shell de Python para usted. Necesitas configurar el controlador de URL para / remote_api en tu app.yamlbusca las entidades que te gustaría eliminar, el código se ve algo así como:
from models import Entry query = Entry.all(keys_only=True) entries =query.fetch(1000) db.delete(entries) /# This could bulk delete 1000 entities a time
Actualización 2013-10-28 :
remote_shell_api.py
ha sido reemplazado porremote_api_shell.py
, y debe conectarse conremote_api_shell.py -s your_app_id.appspot.com
, de acuerdo con la documentación .Hay una nueva característica experimental Administrador de Datastore , después de habilitarlo en la configuración de la aplicación, puede eliminar en bloque y hacer una copia de seguridad de su almacén de datos a través de la interfaz de usuario web.
Estaba tan frustrado con las soluciones existentes para eliminar todos los datos en el almacén de datos en vivo que creé una pequeña aplicación GAE que puede eliminar bastante cantidad de datos en 30 segundos.
Cómo instalar etc: https://github.com/xamde/xydra
Existen varias formas de eliminar entradas del Datastore de App Engine:
Primero, piense si realmente necesita eliminar entradas. Esto es costoso y podría ser más barato no eliminarlos.
Puede eliminar todas las entradas a mano usando el Administrador de Datastore.
Puede utilizar la API remota y eliminar entradas de forma interactiva.
Puede eliminar las entradas mediante programación utilizando un par de líneas de código.
Puede eliminarlos a granel utilizando Task Queues and Cursors.
O puede usar Mapreduce para obtener algo más robusto y elegante.
Cada uno de estos métodos se explica en la siguiente publicación de blog: http://www.shiftedup.com/2015/03/28/how-to-bulk-delete-entries-in-app-engine-datastore
¡Espero eso ayude!
La forma de configuración cero para hacer esto es enviar una solicitud HTTP de ejecución de código arbitrario al servicio de administración que la aplicación en ejecución ya tiene, automáticamente:
import urllib
import urllib2
urllib2.urlopen(''http://localhost:8080/_ah/admin/interactive/execute'',
data = urllib.urlencode({''code'' : ''from google.appengine.ext import db/n'' +
''db.delete(db.Query())''}))
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());
}
EDITAR:
Desde SDK 1.3.8, hay una función de administrador de Datastore para este propósito
Para Python, 1.3.8 incluye un administrador experimental incorporado para esto. say : "habilite el siguiente comando integrado en su archivo app.yaml:"
builtins:
- datastore_admin: on
"Datastore delete actualmente solo está disponible con el tiempo de ejecución de Python. Sin embargo, las aplicaciones Java aún pueden aprovechar esta característica al crear una versión de aplicación Python no predeterminada que habilita Datastore Admin en la aplicación.yaml. Se incluirá soporte nativo para Java. en un próximo lanzamiento ".
Para cualquier almacén de datos que esté en el motor de la aplicación, en lugar de local, puede usar la nueva API de Datastore . Aquí hay un manual para comenzar .
Escribí un script que elimina todas las entidades no incorporadas. La API está cambiando bastante rápido, así que como referencia, la 990ab5c7f2063e8147bcc56ee222836fd3d6e15b en commit 990ab5c7f2063e8147bcc56ee222836fd3d6e15b
from gcloud import datastore
from gcloud.datastore import SCOPE
from gcloud.datastore.connection import Connection
from gcloud.datastore import query
from oauth2client import client
def get_connection():
client_email = ''[email protected]''
private_key_string = open(''/path/to/yourfile.p12'', ''rb'').read()
svc_account_credentials = client.SignedJwtAssertionCredentials(
service_account_name=client_email,
private_key=private_key_string,
scope=SCOPE)
return Connection(credentials=svc_account_credentials)
def connect_to_dataset(dataset_id):
connection = get_connection()
datastore.set_default_connection(connection)
datastore.set_default_dataset_id(dataset_id)
if __name__ == "__main__":
connect_to_dataset(DATASET_NAME)
gae_entity_query = query.Query()
gae_entity_query.keys_only()
for entity in gae_entity_query.fetch():
if entity.kind[0] != ''_'':
print entity.kind
entity.key.delete()
Para el servidor de desarrollo, en lugar de ejecutar el servidor a través del iniciador del motor de la aplicación google, puede ejecutarlo desde la terminal como:
dev_appserver.py --port = [portnumber] --clear_datastore = yes [nameofapplication]
por ejemplo: mi aplicación "reader" se ejecuta en el puerto 15080. Después de modificar el código y reiniciar el servidor, simplemente ejecuto "dev_appserver.py --port = 15080 --clear_datastore = yes reader".
Es bueno para mí.
Para java
DatastoreService db = DatastoreServiceFactory.getDatastoreService();
List<Key> keys = new ArrayList<Key>();
for(Entity e : db.prepare(new Query().setKeysOnly()).asIterable())
keys.add(e.getKey());
db.delete(keys);
Funciona bien en el servidor de desarrollo
Para todas las personas que necesitan una solución rápida para el servidor de desarrollo (como el momento de escribir en febrero de 2016):
- Detener el servidor de desarrollo.
- Eliminar el directorio de destino .
- Reconstruye el proyecto.
Esto borrará todos los datos del almacén de datos.
Puede borrar el almacén de datos del servidor de desarrollo cuando ejecuta el servidor:
/path/to/dev_appserver.py --clear_datastore=yes myapp
También puede abreviar --clear_datastore
con -c
.
Puede eliminar todo el almacén de datos borrando todos los tipos uno a uno. con google appengine tablero de instrumentos. Por favor sigue estos pasos.
- Inicie sesión en https://console.cloud.google.com/datastore/settings
- Haga clic en Abrir administrador de Datastore . (Habilítelo si no está habilitado)
- Seleccione todas las entidades y presione eliminar. (Este paso ejecutar un mapa reduce trabajo para eliminar todas las clases seleccionadas.)
para obtener más información, consulte esta imagen http://storage.googleapis.com/bnifsc/Screenshot%20from%202015-01-31%2023%3A58%3A41.png
Puedes hacerlo usando la interfaz web. Inicie sesión en su cuenta, navegue con enlaces en el lado izquierdo. En la administración del Almacén de datos, tiene opciones para modificar y eliminar datos. Usa las opciones respectivas.
Si está hablando del almacén de datos en vivo , abra el tablero para su aplicación (inicie sesión en appengine), luego datastore -> dataviewer, seleccione todas las filas de la tabla que desea eliminar y presione el botón Eliminar (tendrá que haz esto para todas tus mesas). Puede hacer lo mismo mediante programación mediante remote_api (pero nunca lo he usado).
Si está hablando del almacén de datos de desarrollo , simplemente tendrá que eliminar el siguiente archivo: "./WEB-INF/appengine-generated/local_db.bin" . El archivo se generará para usted nuevamente la próxima vez que ejecute el servidor de desarrollo y tendrá un db claro.
Asegúrese de limpiar su proyecto después.
Este es uno de los pequeños inconvenientes que son útiles cuando comienzas a jugar con Google Application Engine. Encontrarás objetos persistentes en el almacén de datos y luego cambiarás el modelo de objetos JDO para tus entidades persistentes terminando con datos obsoletos que harán que tu aplicación falle por doquier.
Si está usando ndb, el método que funcionó para mí para borrar el almacén de datos:
ndb.delete_multi(ndb.Query(default_options=ndb.QueryOptions(keys_only=True)))
Si tiene muchos datos, usar la interfaz web podría llevar mucho tiempo. La utilidad App Engine Launcher te permite eliminar todo de una vez con la casilla de verificación "Borrar el almacén de datos al iniciar". Esta utilidad ahora está disponible para Windows y Mac (framework de Python).
Si tiene una gran cantidad de datos, debe usar un script para eliminarlo. Sin embargo, puedes usar remote_api para limpiar el almacén de datos del lado del cliente.
Variación de PHP:
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
define(''DATASTORE_SERVICE'', DatastoreServiceFactory::getDatastoreService());
function get_all($kind) {
$query = new Query($kind);
$prepared = DATASTORE_SERVICE->prepare($query);
return $prepared->asIterable();
}
function delete_all($kind, $amount = 0) {
if ($entities = get_all($kind)) {
$r = $t = 0;
$delete = array();
foreach ($entities as $entity) {
if ($r < 500) {
$delete[] = $entity->getKey();
} else {
DATASTORE_SERVICE->delete($delete);
$delete = array();
$r = -1;
}
$r++; $t++;
if ($amount && $amount < $t) break;
}
if ($delete) {
DATASTORE_SERVICE->delete($delete);
}
}
}
Sí, llevará tiempo y 30 seg. es un limite Estoy pensando en poner una muestra de la aplicación ajax para automatizar más allá de 30 segundos.
Esto es lo que estás buscando ...
db.delete(Entry.all(keys_only=True))
Ejecutar una consulta de solo teclas es mucho más rápido que una búsqueda completa, y su cuota tendrá un impacto menor porque las consultas de solo claves se consideran operaciones pequeñas.
Aquí hay un enlace a una respuesta de Nick Johnson que lo describe más.
A continuación se muestra una solución de API REST de extremo a extremo para truncar una tabla ...
Configuré una API REST para manejar las transacciones de la base de datos donde las rutas se asignan directamente al modelo / acción adecuado. Esto se puede invocar ingresando la URL correcta (example.com/inventory/truncate) e iniciando sesión.
Aquí está la ruta:
Route(''/inventory/truncate'', DataHandler, defaults={''_model'':''Inventory'', ''_action'':''truncate''})
Aquí está el controlador:
class DataHandler(webapp2.RequestHandler):
@basic_auth
def delete(self, **defaults):
model = defaults.get(''_model'')
action = defaults.get(''_action'')
module = __import__(''api.models'', fromlist=[model])
model_instance = getattr(module, model)()
result = getattr(model_instance, action)()
Comienza cargando el modelo dinámicamente (es decir, Inventario encontrado en api.models), luego llama al método correcto (Inventory.truncate ()) como se especifica en el parámetro de acción.
El @basic_auth es un decorador / envoltorio que proporciona autenticación para operaciones confidenciales (es decir, POST / DELETE). También hay un decorador de OAuth disponible si le preocupa la seguridad.
Finalmente, la acción se llama:
def truncate(self):
db.delete(Inventory.all(keys_only=True))
Parece mágico, pero en realidad es muy sencillo. La mejor parte es que delete () se puede reutilizar para gestionar la eliminación de uno o muchos resultados agregando otra acción al modelo.
for amodel in db.Model.__subclasses__():
dela=[]
print amodel
try:
m = amodel()
mq = m.all()
print mq.count()
for mw in mq:
dela.append(mw)
db.delete(dela)
#~ print len(dela)
except:
pass
Continuando con la idea de svpino, es prudente reutilizar los registros marcados como eliminar. (su idea no era eliminar, sino marcar como registros "no utilizados"). Un poco de caché / memcache para manejar la copia de trabajo y escribir solo la diferencia de estados (antes y después de la tarea deseada) en el almacén de datos lo mejorará. para tareas grandes, es posible escribir fragmentos de diferencias inmediatas en el almacén de datos para evitar la pérdida de datos si desaparecía Memcache. para que sea a prueba de pérdidas, es posible verificar la integridad / existencia de los resultados de memcached y reiniciar la tarea (o la parte requerida) para repetir los cálculos faltantes. cuando la diferencia de datos se escribe en el almacén de datos, los cálculos requeridos se descartan en la cola.
Otra idea similar al mapa reducido es el tipo de entidad de fragmento de varios tipos de entidades diferentes, por lo que se recopilarán juntos y se mostrarán como entidad única para el usuario final.las entradas solo se marcan como "eliminadas".cuando las entradas "eliminadas" ascienden por fragmento supera algún límite, las entradas "vivas" se distribuyen entre otros fragmentos, y este fragmento se cierra para siempre y luego se borra manualmente de la consola de desarrollo (adivinar a menor costo)upd: parece que no hay tabla desplegable en la consola solo elimine registro por registro a precio regular.es posible eliminar mediante consulta por segmentos un gran conjunto de registros sin que gae falle (al menos funciona localmente) con la posibilidad de continuar en el siguiente intento cuando el tiempo se acaba:
qdelete.getFetchPlan().setFetchSize(100);
while (true)
{
long result = qdelete.deletePersistentAll(candidates);
LOG.log(Level.INFO, String.format("deleted: %d", result));
if (result <= 0)
break;
}
- también a veces es útil hacer un campo adicional en la tabla primaria en lugar de colocar candidatos (registros relacionados) en una tabla separada. y sí, el campo puede ser array no indexado / serializado con un pequeño costo de cálculo.