分页和多个关系实体索引与AppEngine

分页和多个关系实体索引与AppEngine

问题描述:

这是一个关于与包含多个实体索引的模型分页的常见问题。举一个例子,这很容易,所以让我们考虑Brett Slatkin在其视频中提供的示例(http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html)。分页和多个关系实体索引与AppEngine

你有你的消息模型(我忽略了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不允许在多个领域的不平等过滤器,我们必须将模型分解成额外的索引。所以,现在我们已经为发布和到期字段的索引,给我们以下车型(含消息实例是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”过滤器。更糟糕的是,如果我想分页(即“计数”结果来自“偏移量”),则必须手动丢弃第一个“偏移”结果,然后进行相交。当然必须有一个更简单(更聪明)的方式来做到这一点。有任何想法吗?它足够糟糕GAE不允许在多个字段上使用不等式过滤器(尽管出于效率的原因),但是必须手动完成所有的Zig-zags效率似乎相当低效(更不要说运行cpu和时间限制)。

+0

我不完全理解这个问题。也许代码示例混淆了? – max 2010-10-24 16:16:59

+0

对不起。我的帖子不知何故被切断了,所以我重新输入了丢失的位。 – Sri 2010-10-25 00:03:22

在你的情况,我会创建一个单一的关系指数实体

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

其中的关键字列表中每个项目将在格式<属性> = <值>

如:关键词= [“published = 2011-03-24”,“expires = 2011-03-25”]

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

对GAE进行优化始终是一项挑战。但它很有趣,也很有收获。