Comment supprimer toute la banque de données dans Google App Engine?

122

Quelqu'un sait-il comment supprimer tous les magasins de données dans Google App Engine ?

Dan McGrath
la source
2
db.delete (db.Query (keys_only = True)). Plus de détails ici stackoverflow.com/a/10856555/290340 .
Evan Plaice
4
Comme indiqué par @systempuntoout ci-dessous, GAE dispose désormais d'un administrateur Datastore qui vous permet de supprimer des entités en bloc sans aucun codage, entre autres. Cette fonctionnalité doit être mise en évidence ici plutôt qu'enterrée dans le troisième commentaire.
ralfoide
L'administrateur du magasin de données ne fonctionne pas (la page charge une iframe sur un hôte inexistant), nous aurions donc toujours besoin d'utiliser la méthode db.delete.
Pour supprimer toutes les données sur le serveur de développement, /path/to/google_appengine/dev_appserver.py --clear_datastore yes myappname/ émettez ce qui suit à l'invite cmd: où myappname est votre répertoire contenant votre fichier app.yaml pour l'application .. vous devez accéder à ce chemin d'accès au répertoire .. crédit: Steven Almeroth et Melllvar pour la réponse ci-dessous
gsinha

Réponses:

69

Si vous parlez de la banque de données en direct , ouvrez le tableau de bord de votre application (connectez-vous sur appengine) puis datastore -> dataviewer, sélectionnez toutes les lignes de la table que vous souhaitez supprimer et appuyez sur le bouton de suppression (vous devrez faites ceci pour toutes vos tables). Vous pouvez faire la même chose par programmation via remote_api (mais je ne l'ai jamais utilisé).

Si vous parlez de la banque de données de développement , il vous suffira de supprimer le fichier suivant: "./WEB-INF/appengine-generated/local_db.bin" . Le fichier sera généré à nouveau pour vous la prochaine fois que vous exécuterez le serveur de développement et vous aurez une base de données claire.

Assurez-vous de nettoyer votre projet par la suite.

C'est l'un des petits pièges qui vous sont utiles lorsque vous commencez à jouer avec Google Application Engine. Vous vous retrouverez avec des objets persistants dans la banque de données, puis en changeant le modèle d'objet JDO pour vos entités persistantes, se terminant par des données obsolètes qui feront planter votre application partout.

JohnIdol
la source
16
Il y a un paramètre -c dans le dev_appserver.py à supprimer du magasin de données de développement.
svrist
1
@svrist Mais cela ne s'applique qu'au moteur d'application Python. Quelqu'un sait-il comment un raccourci pour le faire en Java? (En attendant, la suggestion de JohnIdol fonctionne bien.)
mgiuca
2
Merci @John: Où est le chemin exact dans MAC OSX?
George Nguyen
3
Où est le chemin dans Windows?
Shane Best
2
@ShaneBest le chemin dans Windows est quelque chose comme ./target/yourappid-1.0-SNAPSHOT/WEB-INF/appengine-generated/local_db.bin
morpheus
58

La meilleure approche est la méthode API à distance suggérée par Nick, c'est un ingénieur App Engine de Google , alors faites-lui confiance.

Ce n'est pas si difficile à faire, et le dernier SDK 1.2.5 fournit le remote_shell_api.py prêt à l'emploi. Alors allez télécharger le nouveau SDK. Suivez ensuite les étapes:

  • connectez le serveur distant dans votre ligne de commande: remote_shell_api.py yourapp /remote_api le shell vous demandera vos informations de connexion et, s'il est autorisé, créera un shell Python pour vous. Vous avez besoin du gestionnaire d'URL de configuration pour / remote_api dans votre app.yaml

  • récupérez les entités que vous souhaitez supprimer, le code ressemble à quelque chose comme:

    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

Mise à jour 28/10/2013 :

  • remote_shell_api.pya été remplacé par remote_api_shell.py, et vous devez vous connecter avec remote_api_shell.py -s your_app_id.appspot.com, selon la documentation .

  • Il existe une nouvelle fonctionnalité expérimentale Administrateur de magasin de données , après l'avoir activée dans les paramètres de l'application, vous pouvez supprimer en bloc et sauvegarder votre banque de données via l'interface utilisateur Web.

Juvenn Woo
la source
17
En fait, vous n'avez pas besoin d'aller chercher. Juste db.delete (Entry.all ()) le fera.
télécharger
4
Vous devez le faire dans 500 ensembles d'entités sinon vous obtiendrez: BadRequestError: ne peut pas supprimer plus de 500 entités en un seul appel
marcc
1
Juste un FYI, pour que vous puissiez utiliser l'API distante, vous devez d'abord l'activer dans votre application en utilisant les fonctions intégrées: - remote_api: dans votre fichier YAML. plus d'informations sur developer.google.com/appengine/articles/remote_api
Zaffiro
2
Ajoutez au moins le 'keys_only = True' lorsque vous appelez Entry.all (). Il n'est pas nécessaire de récupérer toute l'entrée si vous n'avez pas besoin de vérifier les données. Sinon, vous perdez juste des cycles de calcul.
Evan Plaice
1
+1 ... mais: depuis 2013, remote_shell_api.py n'existe pas. Le nom du script actuel est remote_api_shell.py. De plus, si vous utilisez ndb (ce que la plupart des gens font de nos jours), méthode recommandée pour utiliser ndb.delete_multi (model.Entry.query (). Fetch (keys_only = True))
Uri
27

Le moyen le plus rapide et le plus efficace de gérer la suppression groupée sur Datastore consiste à utiliser la nouvelle API de mappage annoncée sur la dernière interface d'E / S Google .

Si votre langue de choix est Python , il vous suffit d'enregistrer votre mappeur dans un fichier mapreduce.yaml et de définir une fonction comme celle-ci:

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

Sur Java, vous devriez jeter un œil à cet article qui suggère une fonction comme celle-ci:

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

EDIT:
Depuis le SDK 1.3.8, il existe une fonctionnalité d'administration de Datastore à cet effet

systempuntoout
la source
27

Vous pouvez effacer la banque de données du serveur de développement lorsque vous exécutez le serveur:

/path/to/dev_appserver.py --clear_datastore=yes myapp

Vous pouvez également abréger --clear_datastoreavec -c.

Steven Almeroth
la source
5
Je ne sais pas si c'est une chose récente, mais la syntaxe réelle est maintenant /path/to/google_appengine/dev_appserver.py --clear_datastore yes myappname/(notez le `` oui '')
Melllvar
C'est le moyen le plus utile de supprimer à plusieurs reprises la banque de données pendant le développement. Avec les options devenant rapidement obsolètes, il convient de souligner que cet indicateur est toujours en place en juillet 2018 et fonctionne pour dev_appserver installé via gcloud CLI
Michael
Dans la version 270.0.0 du SDK Google Cloud "--clear_datastore = yes" fonctionne toujours avec le signe égal
franksands le
15

Si vous disposez d'une quantité importante de données, vous devez utiliser un script pour les supprimer. Cependant, vous pouvez utiliser remote_api pour effacer la banque de données du côté client de manière simple.

Nick Johnson
la source
11

Et voilà: Accédez à Administration de la banque de données, puis sélectionnez le type d'entité que vous souhaitez supprimer et cliquez sur Supprimer. Mapreduce se chargera de la suppression!

David
la source
9

Vous pouvez utiliser plusieurs méthodes pour supprimer des entrées du magasin de données App Engine:

entrez la description de l'image ici

  1. Tout d'abord, demandez-vous si vous devez vraiment supprimer des entrées. Cela coûte cher et il peut être moins coûteux de ne pas les supprimer.

  2. Vous pouvez supprimer toutes les entrées manuellement à l'aide de l'Admin du magasin de données.

  3. Vous pouvez utiliser l'API distante et supprimer des entrées de manière interactive.

  4. Vous pouvez supprimer les entrées par programme à l'aide de quelques lignes de code.

  5. Vous pouvez les supprimer en bloc à l'aide des files d'attente de tâches et des curseurs.

  6. Ou vous pouvez utiliser Mapreduce pour obtenir quelque chose de plus robuste et plus sophistiqué.

Chacune de ces méthodes est expliquée dans le billet de blog suivant: http://www.shiftedup.com/2015/03/28/how-to-bulk-delete-entries-in-app-engine-datastore

J'espère que ça aide!

svpino
la source
6

La méthode de configuration zéro pour ce faire consiste à envoyer une requête HTTP d'exécution de code arbitraire au service d'administration que votre application en cours d'exécution a déjà, automatiquement:

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())'}))
dfichter
la source
Cela ne fonctionne que pour le serveur de développement. Existe-t-il un équivalent de production?
Gady
3

La source

J'ai eu ça de http://code.google.com/appengine/articles/remote_api.html .

Créer la console interactive

Tout d'abord, vous devez définir une console Appenginge interactive. Alors, créez un fichier appelé appengine_console.py et entrez ceci:

#!/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())



Créer la classe de base Mapper

Une fois que cela est en place, créez cette classe Mapper. Je viens de créer un nouveau fichier appelé utils.py et j'ai jeté ceci:

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)

Mapper est censé être simplement une classe abstraite qui vous permet d'itérer sur chaque entité d'un type donné, que ce soit pour extraire leurs données, ou pour les modifier et stocker les entités mises à jour dans le magasin de données.

Courez avec!

Maintenant, démarrez votre console interactive appengine:

$python appengine_console.py <app_id_here>

Cela devrait démarrer la console interactive. Dans celui-ci, créez une sous-classe de Model:

from utils import Mapper
# import your model class here 
class MyModelDeleter(Mapper):
    KIND = <model_name_here>

    def map(self, entity):
        return ([], [entity])

Et, enfin, lancez-le (depuis votre console interactive): mapper = MyModelDeleter () mapper.run ()

C'est tout!

Gezim
la source
3

Vous pouvez le faire en utilisant l'interface Web. Connectez-vous à votre compte, naviguez avec des liens sur le côté gauche. Dans la gestion du magasin de données, vous avez des options pour modifier et supprimer des données. Utilisez les options respectives.

Priyank
la source
3

J'ai créé un panneau de complément qui peut être utilisé avec vos applications App Engine déployées. Il répertorie les types qui sont présents dans la banque de données dans une liste déroulante, et vous pouvez cliquer sur un bouton pour planifier des «tâches» qui suppriment toutes les entités d'un type spécifique ou simplement tout. Vous pouvez le télécharger ici:
http://code.google.com/p/jobfeed/wiki/Nuke

Kostmo
la source
3

Pour Python, la 1.3.8 inclut un administrateur expérimental intégré pour cela. Ils disent : "activez la fonction intégrée suivante dans votre fichier app.yaml:"

builtins:
- datastore_admin: on

"La suppression de la banque de données n'est actuellement disponible qu'avec le moteur d'exécution Python. Les applications Java, cependant, peuvent toujours profiter de cette fonctionnalité en créant une version d'application Python autre que celle par défaut qui active l'administration de la banque de données dans le fichier app.yaml. La prise en charge native de Java sera incluse dans une prochaine version. "

dfrankow
la source
L'ajout de la configuration dans app.yaml a généré une erreur. Au lieu de cela, nous pouvons l'activer à partir de la page «Paramètres des applications» dans la section «Administration». Il y a un bouton pour l'activer
Sundeep
3

Ouvrez "Administration de la banque de données" pour votre application et activez Admin. Ensuite, toutes vos entités seront répertoriées avec des cases à cocher. Vous pouvez simplement sélectionner les entités indésirables et les supprimer.

Girish007
la source
3

C'est ce que vous recherchez ...

db.delete(Entry.all(keys_only=True))

L'exécution d'une requête de clés uniquement est beaucoup plus rapide qu'une extraction complète, et votre quota prendra un coup moins important car les requêtes de clés uniquement sont considérées comme de petites opérations.

Voici un lien vers une réponse de Nick Johnson qui la décrit plus en détail.

Vous trouverez ci-dessous une solution API REST de bout en bout pour tronquer une table ...

J'ai configuré une API REST pour gérer les transactions de base de données où les routes sont directement mappées vers le modèle / action approprié. Cela peut être appelé en entrant la bonne URL (example.com/inventory/truncate) et en vous connectant.

Voici l'itinéraire:

Route('/inventory/truncate', DataHandler, defaults={'_model':'Inventory', '_action':'truncate'})

Voici le gestionnaire:

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

Il commence par charger le modèle dynamiquement (c'est-à-dire Inventory trouvé sous api.models), puis appelle la méthode correcte (Inventory.truncate ()) comme spécifié dans le paramètre action.

@Basic_auth est un décorateur / wrapper qui fournit une authentification pour les opérations sensibles (c'est-à-dire POST / DELETE). Un décorateur oAuth est également disponible si vous êtes préoccupé par la sécurité.

Enfin, l'action s'appelle:

def truncate(self):
  db.delete(Inventory.all(keys_only=True))

Cela ressemble à de la magie mais c'est en fait très simple. La meilleure partie est que delete () peut être réutilisé pour gérer la suppression d'un ou plusieurs résultats en ajoutant une autre action au modèle.

Plie d'Evan
la source
3

Vous pouvez supprimer tous les magasins de données en supprimant tous les types un par un. avec le tableau de bord google appengine. Veuillez suivre ces étapes.

  1. Connectez-vous à https://console.cloud.google.com/datastore/settings
  2. Cliquez sur Open Datastore Admin . (Activez-le s'il n'est pas activé.)
  3. Sélectionnez toutes les entités et appuyez sur Supprimer. (Cette étape exécute un travail de réduction de carte pour supprimer tous les types sélectionnés.)

pour plus d'informations, voir cette image http://storage.googleapis.com/bnifsc/Screenshot%20from%202015-01-31%2023%3A58%3A41.png

vinay mavi
la source
2

Si vous avez beaucoup de données, l'utilisation de l'interface Web peut prendre du temps. L' utilitaire App Engine Launcher vous permet de tout supprimer en une seule fois avec la case à cocher "Effacer la banque de données au lancement". Cet utilitaire est désormais disponible pour Windows et Mac (framework Python).

lucratif
la source
2

Pour le serveur de développement, au lieu d'exécuter le serveur via le lanceur du moteur d'application Google, vous pouvez l'exécuter à partir du terminal comme:

dev_appserver.py --port = [numéro_port] --clear_datastore = yes [nomd'application]

ex: mon application "reader" tourne sur le port 15080. Après avoir modifié le code et redémarré le serveur, je lance juste "dev_appserver.py --port = 15080 --clear_datastore = yes reader".

C'est bon pour moi.

user1552891
la source
1

Je ne veux souvent pas supprimer tout le magasin de données, donc je tire une copie propre de /war/WEB-INF/local_db.bin sur le contrôle de source. C'est peut-être juste moi, mais il semble que même avec le mode de développement arrêté, je dois physiquement supprimer le fichier avant de le tirer. Ceci est sur Windows en utilisant le plugin subversion pour Eclipse.

Dominique
la source
0

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

Oui, cela prendra du temps et 30 secondes. est une limite. Je pense mettre un exemple d'application ajax à automatiser au-delà de 30 secondes.

MarkokraM
la source
Ce n'est même pas un php valide. import? Définition d'une constante comme instance d'objet?
Josh J
0
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
JQuery Guru
la source
0

Si vous utilisez ndb, la méthode qui a fonctionné pour moi pour effacer le magasin de données:

ndb.delete_multi(ndb.Query(default_options=ndb.QueryOptions(keys_only=True)))
Gilad Beeri
la source
1
Je ne pense pas que cela fonctionnera. Appengine se plaint de Sorry, unexpected error: The kind "__Stat_Kind__" is reserved.Cela semble que Appengine a une entité statistique interne qui peut être exposée par cette méthode (bogue possible de leur côté?)
disparu le
0

Pour tout magasin de données qui se trouve sur le moteur d'application, plutôt que local, vous pouvez utiliser la nouvelle API Datastore . Voici un guide pour commencer .

J'ai écrit un script qui supprime toutes les entités non intégrées. L'API change assez rapidement, donc pour référence, je l'ai clonée au 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()
Yonatan Kogan
la source
0
  • poursuivant l'idée de svpino, il est sage de réutiliser les enregistrements marqués comme supprimés. (son idée n'était pas de supprimer, mais de marquer comme "supprimés" les enregistrements inutilisés). un peu de cache / memcache pour gérer la copie de travail et écrire uniquement la différence d'états (avant et après la tâche souhaitée) dans le magasin de données le rendra meilleur. pour les grandes tâches, il est possible d'écrire des morceaux de différence immédiate dans la banque de données pour éviter la perte de données si Memcache disparaissait. pour le rendre à l'épreuve des pertes, il est possible de vérifier l'intégrité / l'existence des résultats memcached et de redémarrer la tâche (ou la partie requise) pour répéter les calculs manquants. lorsque la différence de données est écrite dans la banque de données, les calculs requis sont ignorés dans la file d'attente.

  • Une autre idée similaire à la carte réduite est de partitionner le type d'entité en plusieurs types d'entités différents, de sorte qu'il sera collecté ensemble et visible en tant que type d'entité unique pour l'utilisateur final. les entrées sont uniquement marquées comme "supprimées". lorsque le nombre d'entrées "supprimées" par partition dépasse une certaine limite, les entrées "vivantes" sont distribuées entre d'autres partitions, et cette partition est fermée pour toujours puis supprimée manuellement de la console de développement (devinez à moindre coût) upd: ne semble pas déposer de table sur la console, supprimer uniquement enregistrement par enregistrement au prix régulier.

  • il est possible de supprimer par requête par blocs un grand ensemble d'enregistrements sans échec de gae (au moins fonctionne localement) avec possibilité de continuer à la prochaine tentative lorsque le temps est écoulé:


    qdelete.getFetchPlan().setFetchSize(100);

    while (true)
    {
        long result = qdelete.deletePersistentAll(candidates);
        LOG.log(Level.INFO, String.format("deleted: %d", result));
        if (result <= 0)
            break;
    }
  • il est également parfois utile de créer un champ supplémentaire dans la table principale au lieu de placer les candidats (enregistrements associés) dans une table séparée. et oui, le champ peut être un tableau non indexé / sérialisé avec un faible coût de calcul.
Dmitry Bryliuk
la source
0

Pour toutes les personnes qui ont besoin d'une solution rapide pour le serveur de développement (au moment de la rédaction en février 2016):

  1. Arrêtez le serveur de développement.
  2. Supprimer la cible répertoire .
  3. Reconstruisez le projet.

Cela effacera toutes les données de la banque de données.

alexanderb14
la source
0

J'étais tellement frustré par les solutions existantes pour supprimer toutes les données dans le magasin de données en direct que j'ai créé une petite application GAE qui peut supprimer une certaine quantité de données dans ses 30 secondes.

Comment installer etc: https://github.com/xamde/xydra

Dr Max Völkel
la source
0

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

Fonctionne bien dans Development Server

Prakash Ayappan
la source
0

Vous avez 2 moyens simples,

# 1: Pour réduire les coûts, supprimez tout le projet

# 2: en utilisant ts-datastore-orm:

https://www.npmjs.com/package/ts-datastore-orm attendent Entity.truncate (); La troncature peut supprimer environ 1K lignes par seconde

Tsang Kin Ho
la source