使用AppEngine进行分页和多个关系实体索引

时间:2010-10-24 12:21:30

标签: google-app-engine pagination entity indexing

这是关于对包含多个实体索引的模型进行分页的一般性问题。通过示例更容易,让我们考虑一下Brett Slatkin在他的视频中提供的示例(http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html)。

你有你的消息模型(我忽略了MessageIndex模型),我还添加了两个额外的属性(用于发布和到期时间)。

class Message(db.Model):
    sender = db.StringProperty()
    body = db.TextProperty()
    published = db.DateTimeProperty()
    expires = db.DateTimeProperty()

现在我有兴趣对多个字段进行过滤,比如说在特定时间窗口中发布的消息。例如

select * from Message where pubished > some_date and expires < some_other_date

由于GAE不允许对多个字段进行不等式过滤,因此我们必须将模型分解为额外的索引。所以现在我们有一个已发布和到期字段的索引,给我们以下模型(Message实例是MessagePublishedIndex和MessageExpiryIndex实例的父代):

class Message(db.Model):
    sender = db.StringProperty()
    body = db.TextProperty()

class MessagePublishedIndex(db.Model):
    published = db.DateTimeProperty()

class MessageExpiryIndex(db.Model):
    expires = db.DateTimeProperty()

以及以下key_only查询:

publish_keys = MessagePublishedIndex.all(key_only = True).filter("published >", some_date)
expire_keys = MessageExpiryIndex.all(key_only = True).filter("expires <", some_other_date)

msgs_by_pubdate = db.get([k.parent() for k in publish_keys])
msgs_by_expiry  = db.get([k.parent() for k in expire_keys])

现在,Il必须对这些列表进行交集,以找到常用的列表以获取特定时间窗口内的所有消息。

这看起来很浪费。有更简单的方法吗?如果索引中的字段是ListProperty,这个问题也会加剧,因为key_only查询不能有“IN”过滤器。更糟糕的是,如果我想要分页(即“计数”结果来自“偏移”),Il必须手动丢弃第一个“偏移”结果,然后进行交叉。当然,必须有一种更简单(更智能)的方法。有任何想法吗? GAE不允许在多个字段上使用不等式过滤器(尽管出于效率原因)已经够糟糕了,但是必须自己手动完成所有的zig-zags似乎效率很低(更不用说在cpu和时间限制上运行)。

1 个答案:

答案 0 :(得分:0)

在您的方案中,我将创建一个关系索引实体

class MessageIndex(db.Model):
    keywords = db.StringListProperty();

其中关键字列表中的每个项目的格式均为&lt; property&gt; =&lt; value&gt;

例如:keywords = [“published = 2011-03-24”,“expires = 2011-03-25”]

您需要自己进行序列化/反序列化以获取属性值。或者,您仍然可以在Message模型中存储属性值,仅用于冗余。但是,该方法不适用于范围查询。 (我没有测试,但你可能可以使用带有前缀的查询来伪造范围查询:u“published = 2010”+ u“\ ufffd”,here is more details

优化GAE始终是一项挑战。但它很有趣,也很有价值。