Python 从Firestore删除收藏的最快方法?
我有一个应用程序,它将数百万个文档加载到一个集合中,使用30-80个工作人员同时加载数据。有时,我发现加载过程并没有顺利完成,对于其他数据库,我可以简单地删除表并重新开始,但对于Firestore集合则不行。我必须列出文档并删除它们,但我还没有找到一种方法来扩展它,使其具有与加载过程相同的容量。我现在要做的是,我有两个AppEngine托管的Flask/Python方法,一个用于获取包含1000个文档的页面,然后传递给另一个方法来删除它们。这样,列出文档的过程不会被删除文档的过程阻止。它仍然需要几天才能完成,这太长了 方法获取文档列表并创建任务以删除它们,该任务是单线程的:Python 从Firestore删除收藏的最快方法?,python,google-app-engine,flask,google-cloud-firestore,Python,Google App Engine,Flask,Google Cloud Firestore,我有一个应用程序,它将数百万个文档加载到一个集合中,使用30-80个工作人员同时加载数据。有时,我发现加载过程并没有顺利完成,对于其他数据库,我可以简单地删除表并重新开始,但对于Firestore集合则不行。我必须列出文档并删除它们,但我还没有找到一种方法来扩展它,使其具有与加载过程相同的容量。我现在要做的是,我有两个AppEngine托管的Flask/Python方法,一个用于获取包含1000个文档的页面,然后传递给另一个方法来删除它们。这样,列出文档的过程不会被删除文档的过程阻止。它仍然需要
@app.route('/delete_collection/<collection_name>/<batch_size>', methods=['POST'])
def delete_collection(collection_name, batch_size):
batch_size = int(batch_size)
coll_ref = db.collection(collection_name)
print('Received request to delete collection {} {} docs at a time'.format(
collection_name,
batch_size
))
num_docs = batch_size
while num_docs >= batch_size:
docs = coll_ref.limit(batch_size).stream()
found = 0
deletion_request = {
'doc_ids': []
}
for doc in docs:
deletion_request['doc_ids'].append(doc.id)
found += 1
num_docs = found
print('Creating request to delete docs: {}'.format(
json.dumps(deletion_request)
))
# Add to task queue
queue = tasks_client.queue_path(PROJECT_ID, LOCATION, 'database-manager')
task_meet = {
'app_engine_http_request': { # Specify the type of request.
'http_method': 'POST',
'relative_uri': '/delete_documents/{}'.format(
collection_name
),
'body': json.dumps(deletion_request).encode(),
'headers': {
'Content-Type': 'application/json'
}
}
}
task_response_meet = tasks_client.create_task(queue, task_meet)
print('Created task to delete {} docs: {}'.format(
batch_size,
json.dumps(deletion_request)
))
@app.route('/delete\u collection/',methods=['POST'])
def delete_集合(集合名称、批次大小):
批次大小=整数(批次大小)
coll\u ref=db.collection(collection\u name)
打印('一次收到删除集合{}{}文档的请求'。格式(
集合名称,
批量大小
))
num\u docs=批量大小
当num\u docs>=批量大小时:
docs=coll\u ref.limit(批量大小).stream()
找到=0
删除请求={
“文档ID”:[]
}
对于文档中的文档:
删除请求['doc\u id'].append(doc.id)
发现+=1
num_docs=已找到
打印('创建删除文档的请求:{}'。格式(
json.dumps(删除请求)
))
#添加到任务队列
queue=tasks\u client.queue\u路径(项目\u ID,位置,'数据库管理器')
任务会议={
'app_engine_http_request':{#指定请求的类型。
“http_方法”:“POST”,
“相对uri”:“/delete_documents/{}”。格式(
集合名称
),
“body”:json.dumps(删除请求).encode(),
“标题”:{
“内容类型”:“应用程序/json”
}
}
}
task\u response\u meet=tasks\u client.创建任务(队列,task\u meet)
打印('已创建任务以删除{}个文档:{}'。格式(
批量大小,
json.dumps(删除请求)
))
下面是我用来删除文档的方法,它可以扩展。实际上,它一次只处理5-10个文档,受其他方法传递要删除的文档ID页面的速率限制。将两者分开有帮助,但没有那么多
@app.route('/delete_documents/<collection_name>', methods=['POST'])
def delete_documents(collection_name):
# Validate we got a body in the POST
if flask.request.json:
print('Request received to delete docs from :{}'.format(collection_name))
else:
message = 'No json found in request: {}'.format(flask.request)
print(message)
return message, 400
# Validate that the payload includes a list of doc_ids
doc_ids = flask.request.json.get('doc_ids', None)
if doc_ids is None:
return 'No doc_ids specified in payload: {}'.format(flask.request.json), 400
print('Received request to delete docs: {}'.format(doc_ids))
for doc_id in doc_ids:
db.collection(collection_name).document(doc_id).delete()
return 'Finished'
if __name__ == '__main__':
# Set environment variables for running locally
app.run(host='127.0.0.1', port=8080, debug=True)
@app.route('/delete_documents/',methods=['POST']))
def delete_文档(集合名称):
#我们在邮局找到一具尸体
如果flask.request.json:
打印('从以下位置删除文档的请求:{}'。格式(集合名称))
其他:
消息='在请求{}中找不到json'。格式(flask.request)
打印(信息)
返回消息,400
#验证有效负载是否包括文档ID列表
doc\u id=flask.request.json.get('doc\u id',无)
如果文档ID为“无”:
返回“负载:{}中未指定文档ID”。格式(flask.request.json),400
打印('收到删除文档的请求:{}'。格式(文档ID))
对于文档id中的文档id:
db.collection(collection\u name).document(doc\u id).delete()
返回“已完成”
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
#设置本地运行的环境变量
app.run(host='127.0.0.1',port=8080,debug=True)
我尝试过运行delete_collection()的多个并发执行,但我不确定这是否有帮助,因为我不确定它是否每次调用limit(batch_size).stream()时都会得到一组不同的文档,或者可能会得到重复的文档
如何使其运行更快?本文介绍了如何使用可调用的云函数在每秒删除多达4000个文档的过程中利用firestore delete命令。以下是我用来测试批量删除的简单Python脚本。就像@Chris32所说的那样,如果延迟不太差,批处理模式每秒将删除数千个文档
from time import time
from uuid import uuid4
from google.cloud import firestore
DB = firestore.Client()
def generate_user_data(entries = 10):
print('Creating {} documents'.format(entries))
now = time()
batch = DB.batch()
for counter in range(entries):
# Each transaction or batch of writes can write to a maximum of 500 documents.
# https://cloud.google.com/firestore/quotas#writes_and_transactions
if counter % 500 == 0 and counter > 0:
batch.commit()
user_id = str(uuid4())
data = {
"some_data": str(uuid4()),
"expires_at": int(now)
}
user_ref = DB.collection(u'users').document(user_id)
batch.set(user_ref, data)
batch.commit()
print('Wrote {} documents in {:.2f} seconds.'.format(entries, time() - now))
def delete_one_by_one():
print('Deleting documents one by one')
now = time()
docs = DB.collection(u'users').where(u'expires_at', u'<=', int(now)).stream()
counter = 0
for doc in docs:
doc.reference.delete()
counter = counter + 1
print('Deleted {} documents in {:.2f} seconds.'.format(counter, time() - now))
def delete_in_batch():
print('Deleting documents in batch')
now = time()
docs = DB.collection(u'users').where(u'expires_at', u'<=', int(now)).stream()
batch = DB.batch()
counter = 0
for doc in docs:
counter = counter + 1
if counter % 500 == 0:
batch.commit()
batch.delete(doc.reference)
batch.commit()
print('Deleted {} documents in {:.2f} seconds.'.format(counter, time() - now))
generate_user_data(10)
delete_one_by_one()
print('###')
generate_user_data(10)
delete_in_batch()
print('###')
generate_user_data(2000)
delete_in_batch()
从时间导入时间
从uuid导入uuid4
从google.cloud导入firestore
DB=firestore.Client()
def生成用户数据(条目=10):
打印('创建{}个文档'。格式化(条目))
现在=时间()
batch=DB.batch()
对于范围内的计数器(条目):
#每个事务或写入批最多可写入500个文档。
# https://cloud.google.com/firestore/quotas#writes_and_transactions
如果计数器%500==0且计数器>0:
batch.commit()
user_id=str(uuid4())
数据={
“一些数据”:str(uuid4()),
“过期时间”:int(现在)
}
user\u ref=DB.collection(u'users').document(user\u id)
批处理设置(用户参考,数据)
batch.commit()
打印({.2f}秒内写入{}个文档。。格式(条目,time()-now))
def按一个删除一个:
打印('逐个删除文档')
现在=时间()
docs=DB.collection(u'users')。where(u'expires_at',u'这是我想到的。它不是很快(每秒120-150个文档),但我在python中找到的所有其他示例根本不起作用:
now = datetime.now()
then = now - timedelta(days=DOCUMENT_EXPIRATION_DAYS)
doc_counter = 0
commit_counter = 0
limit = 5000
while True:
docs = []
print('Getting next doc handler')
docs = [snapshot for snapshot in db.collection(collection_name)
.where('id.time', '<=', then)
.limit(limit)
.order_by('id.time', direction=firestore.Query.ASCENDING
).stream()]
batch = db.batch()
for doc in docs:
doc_counter = doc_counter + 1
if doc_counter % 500 == 0:
commit_counter += 1
print('Committing batch {} from {}'.format(commit_counter, doc.to_dict()['id']['time']))
batch.commit()
batch.delete(doc.reference)
batch.commit()
if len(docs) == limit:
continue
break
print('Deleted {} documents in {} seconds.'.format(doc_counter, datetime.now() - now))
now=datetime.now()
然后=现在-时间增量(天=文档\u到期\u天)
doc\u计数器=0
提交计数器=0
限额=5000
尽管如此:
文档=[]
打印('获取下一个文档处理程序')
docs=[数据库集合中快照的快照(集合名称)
.where('id.time','是的,我看到了,不幸的是,唯一的例子是Node。正在寻找一种用Python实现这一点的方法。在15-20批之后,你没有收到一堆截止日期错误吗?这对我来说很有效,但我需要在它通过所有文档之前经常重试。