我正在尝试迭代查询,我的代码是为DB设置的。现在我正在使用NDB,我对语法感到困惑。基本上在这段代码中,我正在尝试为Search API构建索引。我的数据库很大(约30000个实体),每个实体都将成为一个文档。我认为最好的方法就是使用任务队列分割工作。
无论如何这里是代码:
q = Database.query()
q.filter(Database.title > None)
numEntities = q.count(limit=50000)
logging.info(num)
counter = 0
batchsize = 999
while (counter<numEntities):
logging.info(counter)
if (counter == 0):
resultsFetched = 0
for p in q:
resultsFetched+=1
counter += 1
if p.identifier:
# add code to call worker here
taskqueue.add(queue_name='buildSearchIndexWorker',target='buildsearch',url='/tasks/buildSearchIndexWorker',params={'ID':p.identifier})
if (resultsFetched == batchsize):
a, startCursor, more = q.fetch_page(999)
break
else:
q.fetch_page(999,start_cursor = startCursor)
resultsFetched = 0
for p in q:
resultsFetched+=1
counter += 1
if p.identifier:
# add code to call worker here
taskqueue.add(queue_name='buildSearchIndexWorker',target='buildsearch',url='/tasks/buildSearchIndexWorker',params={'ID':p.identifier})
if (resultsFetched == batchsize):
a, startCursor, more = q.fetch_page(999)
break
基本上从我使用数据库时,我认为每个查询有999次上限。此限制是否仍适用于NDB查询?如果是这样,我希望代码一次执行999次拉取,创建任务队列,然后通过使用游标,拉出下一个999个实体。我编写代码的方式是一种迭代查询对象的适当方式吗?谢谢。
答案 0 :(得分:2)
关于您现有代码的一些评论:
最好避免运行q.count()
。在尝试迭代大型查询时,无法确定在任务超时之前您将能够完成整个迭代。其次,q.count()
,最后一次检查,仅限于1,000个实体。
我要解决这个问题的简单方法是(主要考虑这个伪代码):
def _iterate_and_index(cursor=None):
query = MyModel.query(keys_only=True) # you need to reconstruct your query every time
results, cursor, more = query.fetch_page(BATCH_SIZE or 999, start_cursor=cursor)
# Immediately fire this task to continue this query.
if more:
deferred.defer(_iterate_and_index, cursor)
queue = taskqueue.Queue('buildSearchIndexWorker')
tasks_to_add = []
for entity_key in results:
task = taskqueue.Task(target='buildsearch',
url='/tasks/buildSearchIndexWorker',
params={'entity_key':entity_key.urlsafe()})
tasks_to_add.append(task)
# Add tasks to queue, 100 at a time (100 is the API limit)
while tasks_to_add:
queue.add(tasks_to_add[:100])
tasks_to_add = tasks_to_add[100:]
有些事情需要注意:
.identifier
传递给任务,而是选择使查询使用keys_only
来提高查询效率 - 因为在实际过程中您不需要任何关于实体的数据查询。这将节省您的时间和金钱。more
fetch_page
将无需使用q.count()
。deferred.defer
在实际处理批次之前的下一次迭代。这可以保持并行运行并加速整个操作。它还可以防止你的游标变得陈旧。我建议您查看this simple Mapper库,该库使用延迟任务(也称为taskqueue)来解决大批量迭代,并允许您通过易于实现的模式解决类似问题。
答案 1 :(得分:1)
您查询构造的问题是您还没有阅读有关ndb查询的文档,并假设多步构造与db相同。
q = Database.query()
q.filter(Database.title > None)
numEntities = q.count(limit=50000)
使用ndb,每次调用查询或过滤器都会创建一个新的查询对象,而不是添加到现有查询中。你的代码应该是
q = Database.query()
q = q.filter(Database.title > None)
numEntities = q.count(limit=50000)
其他一些观点
哦,我会在那里停下来,其他答案刚刚出现并覆盖其余部分。