Appengine循环遍历大型数据集

时间:2014-03-08 01:30:54

标签: google-app-engine app-engine-ndb

我需要遍历appengine中的大型数据集。当然,由于数据存储在一段时间后超时,我决定使用任务来解决这个问题,这是试图解释我试图使用的方法:

Initialization of task via http post
0) Create query (entity.query()), and set a batch_size limit (i.e. 500)
1) Check if there are any cursors--if this is the first time running, there won't be any.
2a) If there are no cursors, use iter() with the following options: produce_cursors = true, limit= batch_size
2b) If there are curors, use iter() with same options as 2a + set start_cursor to the cursor.
3) Do a for loop to iterate through the results pulled by iter()
4) Get cursor_after()
5) Queue new task (basically re-run the task that was running) passing the cursor into the payload.

因此,如果此代码以我想要的方式工作,那么在队列中的任何特定时间只能运行1个任务。但是,我今天早上开始运行任务,3个小时后,当我查看队列时,其中有4个任务!这很奇怪,因为新任务只应在启动它的任务结束时启动。

这是没有编辑的实际代码:

class send_missed_swipes(BaseHandler): #disabled
    def post(self):
        """Loops across entire database (as filtered) """
        #Settings
        BATCH_SIZE = 500
        cursor = self.request.get('cursor')
        start = datetime.datetime(2014, 2, 13, 0, 0, 0, 0)
        end = datetime.datetime(2014, 3, 5, 0, 0, 00, 0)

        #Filters
        swipes = responses.query()
        swipes = swipes.filter(responses.date>start)

        if cursor:
            num_updated = int(self.request.get('num_updated'))
            cursor = ndb.Cursor.from_websafe_string(cursor)
            swipes = swipes.iter(produce_cursors=True,limit=BATCH_SIZE,start_cursor=cursor)
        else:
            num_updated = 0
            swipes = swipes.iter(produce_cursors=True,limit=BATCH_SIZE)

        count = 0
        for swipe in swipes:
            count += 1

            if swipe.date>end:
                pass
            else:
                uKey = str(swipe.uuId.urlsafe())
                pKey = str(swipe.pId.urlsafe())
                act = swipe.act
                taskqueue.add(queue_name="analyzeData", url="/admin/analyzeData/send_swipes", params={'act':act,'uKey':uKey,'pKey':pKey})
                num_updated += 1

        logging.info('count = '+str(count))
        logging.info('num updated = '+str(num_updated))
        cursor = swipes.cursor_after().to_websafe_string()
        taskqueue.add(queue_name="default", url="/admin/analyzeData/send_missed_swipes", params={'cursor':cursor,'num_updated':num_updated})

这是一个复杂的问题,如果我需要更好地解释,请告诉我。谢谢你的帮助!

P.S。 app.yaml中的T​​hreadsafe为false

2 个答案:

答案 0 :(得分:1)

我相信任务可以多次执行,因此让您的流程具有幂等性非常重要。

来自doc https://developers.google.com/appengine/docs/python/taskqueue/overview-push

  

请注意,此示例不是幂等的。这项任务是可能的   队列以多次执行任务。在这种情况下,计数器是   每次运行任务时都会增加,可能会导致结果偏差。

您可以使用名称创建任务来处理此问题 https://developers.google.com/appengine/docs/python/taskqueue/#Python_Task_names

我很好奇为什么你的yaml中的线程安全=假?

答案 1 :(得分:1)

有点偏离主题(因为我没有解决你的问题),但这听起来像是map reduce的工作。

关于主题:您可以使用max_concurrent_requests=1创建自定义队列。您仍然可以在队列中拥有多个任务,但一次只能执行一个任务。