2017-03-09 1 views
5

Google App Engine에서 작업 대기열을 사용하려고합니다. App Engine 설명서 "Background work with the deferred library"에 표시된 Mapper 클래스를 활용하고 싶습니다. 나는 키키로 NDB 쿼리를 주문하는 방법은 무엇입니까?

하여 쿼리 결과의 순서에 예외가
def get_query(self): 
    ... 
    q = q.order("__key__") 
    ... 

예외 :

File "C:... mapper.py", line 41, in get_query 
    q = q.order("__key__") 
    File "C:\Program Files (x86)\Google\google_appengine\google\appengine\ext\ndb\query.py", line 1124, in order 
    'received %r' % arg) 
TypeError: order() expects a Property or query Order; received '__key__' 
INFO  2017-03-09 11:56:32,448 module.py:806] default: "POST /_ah/queue/deferred HTTP/1.1" 500 114 

이 문서는 2009 년부터, 그래서 내가 뭔가가 변경되었을 수 같아요. 내 환경 : Windows 7, Python 2.7.9, Google App Engine SDK 1.9.50

NDB에서 주문하는 것에 대해서는 somewhat similar questions이 있습니다. 이 코드는 2017 년 2 월에 업데이트되어 명성으로 SO 사용자의 상위 0.1 % 이내의 사람이 게시 한 공식 문서의 버그입니다.

그래서 나는 틀린 일을해야합니다. 해결 방안은 무엇인가?

+2

시도'Q = q.order (self.KIND.key) 인' –

+0

는'ndb.delete_multi'는 반환'확인'맵을 key''의 목록을 필요로하므로 'to_delete' 키 입력 – blueCat

답변

1

빙고. Avinash Raj가 맞습니다. 대답이라면 받아 들일 것입니다. 이 여기에 전체 클래스 코드

#!/usr/bin/python2.7 
# -*- coding: utf-8 -*- 
from google.appengine.ext import deferred 
from google.appengine.ext import ndb 
from google.appengine.runtime import DeadlineExceededError 
import logging 

class Mapper(object): 
    """ 
    from https://cloud.google.com/appengine/docs/standard/python/ndb/queries 
    corrected with suggestions from Stack Overflow 
    http://stackoverflow.com/questions/42692319/how-to-order-ndb-query-by-the-key 
    """ 
    # Subclasses should replace this with a model class (eg, model.Person). 
    KIND = None 

    # Subclasses can replace this with a list of (property, value) tuples to filter by. 
    FILTERS = [] 

    def __init__(self): 
     logging.info("Mapper.__init__: {}") 
     self.to_put = [] 
     self.to_delete = [] 

    def map(self, entity): 
     """Updates a single entity. 
     Implementers should return a tuple containing two iterables (to_update, to_delete). 
     """ 
     return ([], []) 

    def finish(self): 
     """Called when the mapper has finished, to allow for any final work to be done.""" 
     pass 

    def get_query(self): 
     """Returns a query over the specified kind, with any appropriate filters applied.""" 
     q = self.KIND.query() 
     for prop, value in self.FILTERS: 
      q = q.filter(prop == value) 
     if __name__ == '__main__': 
      q = q.order(self.KIND.key) # the fixed version. The original q.order('__key__') failed 
      # see http://stackoverflow.com/questions/42692319/how-to-order-ndb-query-by-the-key 
     return q 

    def run(self, batch_size=100): 
     """Starts the mapper running.""" 
     logging.info("Mapper.run: batch_size: {}".format(batch_size)) 
     self._continue(None, batch_size) 

    def _batch_write(self): 
     """Writes updates and deletes entities in a batch.""" 
     if self.to_put: 
      ndb.put_multi(self.to_put) 
      self.to_put = [] 
     if self.to_delete: 
      ndb.delete_multi(self.to_delete) 
      self.to_delete = [] 

    def _continue(self, start_key, batch_size): 
     q = self.get_query() 
     # If we're resuming, pick up where we left off last time. 
     if start_key: 
      key_prop = getattr(self.KIND, '_key') 
      q = q.filter(key_prop > start_key) 
     # Keep updating records until we run out of time. 
     try: 
      # Steps over the results, returning each entity and its index. 
      for i, entity in enumerate(q): 
       map_updates, map_deletes = self.map(entity) 
       self.to_put.extend(map_updates) 
       self.to_delete.extend(map_deletes) 
       # Do updates and deletes in batches. 
       if (i + 1) % batch_size == 0: 
        self._batch_write() 
       # Record the last entity we processed. 
       start_key = entity.key 
      self._batch_write() 
     except DeadlineExceededError: 
      # Write any unfinished updates to the datastore. 
      self._batch_write() 
      # Queue a new task to pick up where we left off. 
      deferred.defer(self._continue, start_key, batch_size) 
      return 
     self.finish() 
관련 문제