AppEngine/Python NDB 键的顺序

3 投票
1 回答
1326 浏览
提问于 2025-04-17 19:13

我遇到了一个有趣的问题,这个问题是在我把代码升级到使用NDB之后才出现的。

我在使用gae-sessions,这个工具会把会话的过期时间编码到每个存储在数据库中的会话的键里。举个例子,一个键的格式可能是这样的:1363968220_6ea52c936f16fc557c0c03a5f276a056,其中前10个字符表示会话过期的时间戳(值1363968220表示“2013-03-22 16:03:40”)。

在升级到NDB之前,删除过期会话的代码运行得很好。但在升级之后,这段代码错误地删除了那些还没有过期的会话。代码如下:

time_time = time.time()
now_str = unicode(int(time_time))
now_str_datetime = datetime.datetime.fromtimestamp(time_time) 
q = SessionModel.query(namespace='')
key = ndb.Key(SessionModel, now_str + u'\ufffd', namespace='')
logging.info("Deleting sessions with key values less than %s [%s]" % (key, now_str_datetime))
q.filter(SessionModel._key < key)
results = q.fetch(500, keys_only=True)
# This is for debugging purposes
for r_key in results:
    logging.warning("Deleting key %s" % (r_key))

这段代码的输出结果是:

Deleting sessions with key values less than Key('SessionModel', '1363362698\xef\xbf\xbd') [2013-03-15 15:51:38.767947]
Deleting key Key('SessionModel', '1363924467_e0240e38b4047ef821ac62e07466351b')

如果把这些键当作字符串来处理(使用字符串的排序规则),那么被删除的键(以1363924467开头)应该被认为小于我们要过滤的键(以1363362698开头),所以我对NDB中发生的事情感到困惑,为什么会导致这个问题。

1 个回答

2

这很难解释,基于文档的内容。

https://developers.google.com/appengine/docs/python/ndb/keyclass?hl=zh-tw

键(key)可以进行比较,比如说 key1 == key2 或者 key1 < key2。这些比较会看应用的 ID、命名空间和完整的“祖先路径”。它们的比较顺序和数据存储(Datastore)在查询时按键属性或键排序的方式是一样的。

这里有个速查表:https://docs.google.com/document/d/1AefylbadN456_Z7BZOpZEXDq8cR8LYu7QgI7bt5V0Iw/mobilebasic

还有源代码。所有这些都表明用法应该是没问题的。键会比较应用 ID、命名空间和键对的顺序。也许你可以尝试打印一下 (key.app(), key.namespace(), key.pairs()) 来查看详细信息。

https://code.google.com/p/appengine-ndb-experiment/source/browse/ndb/key.py

def __gt__(self, other):
    """Greater than ordering."""
    if not isinstance(other, Key):
      return NotImplemented
    return self.__tuple() > other.__tuple()

def __tuple(self):
    """Helper to return an orderable tuple."""
    return (self.app(), self.namespace(), self.pairs())

撰写回答