문제

Google App Engine에서 특정 종류에 대한 모든 데이터를 삭제하고 싶습니다.이것을하는 가장 좋은 방법은 무엇입니까?삭제 스크립트 (Hack)를 썼지 만 수백 레코드 후에 데이터가 너무 많아서 시간 초과가 나옵니다.

도움이 되었습니까?

해결책

그만큼 공식 답변 Google에서는 여러 요청에 걸쳐 청크로 나누어 삭제해야 한다는 것입니다.AJAX를 사용할 수 있습니다. 메타 새로고침, 또는 더 이상 개체가 남지 않을 때까지 스크립트에서 URL을 요청하세요.

다른 팁

현재 키로 항목을 삭제하는 중인데 더 빠른 것 같습니다.

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

터미널에서 컬 -N http://...를 실행합니다.

이제 Datastore 관리자를 사용하여 다음을 수행할 수 있습니다. https://developers.google.com/appengine/docs/adminconsole/datastoreadmin#Deleting_Entities_in_Bulk

내가 편집증적인 사람이라면 Google App Engine(GAE)을 사용하면 원하는 경우 데이터를 쉽게 삭제할 수 없다고 말할 것입니다.인덱스 크기와 6GB 데이터를 35GB 스토리지(요금 청구)로 변환하는 방법에 대한 논의는 건너뛰겠습니다.그것은 또 다른 이야기이지만 이를 해결할 수 있는 방법이 있습니다. 즉, 인덱스(자동 생성 인덱스)를 생성할 속성 수를 제한하는 등의 방법이 있습니다.

내가 이 글을 쓰기로 결정한 이유는 샌드박스에 있는 모든 종류를 "핵화"해야 하기 때문입니다.나는 그것에 대해 읽고 마침내 다음 코드를 생각해 냈습니다.

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 팀의 요청:단일 거래에서 같은 종류의 항목을 모두 삭제하는 기능을 추가하세요.

사용해 보세요 App Engine 콘솔 그러면 특별한 코드를 배포할 필요도 없습니다.

아마도 해킹은 다음과 같았을 것입니다.

# 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.5GB) Google App Engine을 사용하지 않는 사용자에게는 그다지 도움이 되지 않습니다.

db.delete(results) 및 App Engine Console을 사용해 보았지만 그 중 아무 것도 작동하지 않는 것 같습니다.10000개가 넘는 항목을 업로드했기 때문에 데이터 뷰어(최대 200개까지 증가된 제한)에서 항목을 수동으로 제거해도 작동하지 않았습니다.이 스크립트 작성을 마쳤습니다.

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)  

비결은 self.redirect를 사용하는 대신 html에 리디렉션을 포함하는 것이었습니다.테이블의 모든 데이터를 제거하기 위해 밤새 기다릴 준비가 되었습니다.앞으로 GAE 팀이 테이블 삭제를 더 쉽게 만들 수 있기를 바랍니다.

Datastore에서 일괄 삭제를 처리하는 가장 빠르고 효율적인 방법은 새로운 매퍼 API 최근에 발표됨 구글 I/O.

선택한 언어가 다음과 같은 경우 파이썬, 매퍼를 mapreduce.yaml 파일을 작성하고 다음과 같은 함수를 정의하십시오.

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

~에 자바 너 좀 봐야 해 이 기사 이는 다음과 같은 기능을 제안합니다.

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

팁 하나.나는 당신이 알고있는 것이 좋습니다 원격_API 이러한 유형의 사용(대량 삭제, 수정 등)에 사용됩니다.그러나 원격 API를 사용하더라도 배치 크기는 한 번에 수백 개로 제한될 수 있습니다.

안타깝게도 대량 삭제를 쉽게 수행할 수 있는 방법은 없습니다.가장 좋은 방법은 호출당 합리적인 수의 항목을 삭제하는 스크립트를 작성한 다음 반복적으로 호출하는 것입니다. 예를 들어 삭제할 데이터가 더 많을 때마다 삭제 스크립트가 302 리디렉션을 반환하도록 한 다음 "wget ​​- -max-redirect=10000"(또는 다른 큰 숫자).

django를 사용하여 설정 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")

Java/JPA를 사용하는 경우 다음과 같이 할 수 있습니다.

    em = EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory)
    Query q = em.createQuery("delete from Table t");
    int number = q.executeUpdate();

Java/JDO 정보는 여기에서 찾을 수 있습니다. http://code.google.com/appengine/docs/java/datastore/queriesandindexes.html#Delete_By_Query

그래 넌 할수있어:데이터 저장소 관리로 이동한 다음 삭제하려는 엔터티 유형을 선택하고 삭제를 클릭합니다.Mapreduce가 삭제를 처리해 드립니다!

개발 서버, 앱 디렉토리로 CD를 이동한 후 다음과 같이 실행할 수 있습니다.

dev_appserver.py --clear_datastore=yes .

그러면 앱이 시작되고 데이터 저장소가 지워집니다.이미 다른 인스턴스가 실행 중인 경우 앱이 필요한 IP에 바인딩할 수 없으므로 시작에 실패하고 데이터 저장소가 지워집니다.

작업 대기열을 사용하여 100개의 개체 청크를 삭제할 수 있습니다.GAE에서 개체를 삭제하면 GAE의 관리 기능이 얼마나 제한되어 있는지 보여줍니다.1000개 이하의 엔터티에 대한 일괄 작업을 수행해야 합니다.csv와 함께 작동하는 벌크로더 도구를 사용할 수 있지만 설명서에서는 Java를 다루지 않습니다.나는 GAE Java를 사용하고 있으며 삭제 전략에는 2개의 서블릿이 포함됩니다. 하나는 실제로 삭제를 수행하고 다른 하나는 작업 대기열을 로드하기 위한 것입니다.삭제를 원할 때 큐 로딩 서블릿을 실행하면 큐가 로드되고 GAE는 큐에 있는 모든 작업을 실행하게 됩니다.

방법:소수의 객체를 삭제하는 서블릿을 만듭니다.작업 대기열에 서블릿을 추가합니다.집에 가거나 다른 일을하십시오.) 데이터 스토어를 자주 확인하십시오 ...

매주 제거하는 개체가 약 5000개 있는 데이터 저장소가 있고 정리하는 데 약 6시간이 걸리므로 금요일 밤에 작업을 실행합니다.나는 동일한 기술을 사용하여 약 12개의 속성이 포함된 약 5000개의 개체로 구성된 데이터를 대량 로드합니다.

이것은 나에게 효과적이었습니다.

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)

여러분 감사합니다. 필요한 것을 얻었습니다.:디
삭제할 DB 모델이 많은 경우 유용할 수 있으며 터미널에서 이를 전달할 수 있습니다.또한, DB_MODEL_LIST에서 삭제 목록을 직접 관리할 수도 있습니다.
DB_1 삭제:

python bulkdel.py 10 DB_1

모든 DB 삭제:

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

물론 파일의 모델에 대한 링크를 매핑해야 합니다(GAE의 main.py와 같은). ;)
나 같은 사람이 세부적으로 필요한 경우를 대비해 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)

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)

자바스크립트에서 다음은 페이지의 모든 항목을 삭제합니다.

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

삭제하려는 엔터티가 있는 관리 페이지(.../_ah/admin)에 있다고 가정합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top