読者です 読者をやめる 読者になる 読者になる

AppEngineでKind(テーブル)を削除する方法

Google App Engineではデータを削除したい時にサーバのデータに対してDelete文を実行したりDrop Tableしたりということができません。Kindをdrop(KindにあるEntity[レコード]を全件削除)するには現時点では削除するコードをサーバにデプロイしてブラウザからリクエストを送ります。そこで使用するソースコードを紹介します。

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.DatastoreTimeoutException;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;

    public static void dropKind(String kindName) {
        DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
        Query query = new Query(kindName);
        query.setKeysOnly();
        List<Entity> list =
            ds.prepare(query).asList(FetchOptions.Builder.withOffset(0)); // ※DatastoreTimeoutException の可能性がありますが省略しています。
        List<Key> keys = new ArrayList<Key>(500);
        for (Entity entity : list) {
            keys.add(entity.getKey());
            if (keys.size() == 500) {
                try {
                    ds.delete(keys); // batch delete
                } catch (DatastoreTimeoutException ignore) {
                }
                keys.clear();
            }
        }
        if (keys.size() > 0){
            ds.delete(keys); // batch delete ※DatastoreTimeoutException の可能性がありますが省略しています。
        }
    }

使い方は簡単でdropKindの引数にKind名を指定するだけです。おそらくJDOを使っている人は下記のようなコードになると思います。
例)dropKind(Emp.class.getSimpleName());

  • 解説
    • KindのKey(PK)を全件取得
      • KindのKeyを取得する際に、query.setKeysOnly();をしています。データ(プロパティ値)が不要な場合はsetKeysOnlyすることで取得が4倍近く早くなります。
    • KeyをListに詰める
      • DatastoreServiceのdeleteは1つのKeyを引数に取ることもできますが、KeyをListに詰めた後にds.delete(keys);する事でbatch deleteとなり高速に削除できます。
    • 500件毎にdelete
      • 500件毎に削除しているのはDatastoreServiceのput(insert/update)およびdeleteは最大500件だからです。
    • ※DatastoreTimeoutExceptionをtry catch。DatastoreTimeoutExceptionが発生したら途中まで消えたり消えなかったりします。

*一応書いておくと、このメソッド一回で確実にKindをDropすることを保証するものではありません。何回も実行して下さいな。もし、これでも件数が多くてだめな場合はTaskQueueで件数を分割して投げまくって下さい。