13

示例问题:

实体:

  • 用户包含姓名和朋友列表(用户参考)
  • 博客文章包含标题、内容、日期和作者(用户)

要求:

我想要一个显示用户朋友最近 10 篇文章的标题和博客链接的页面。我还希望能够继续翻阅旧条目。

SQL解决方案:

所以在 sql 领域它会是这样的:

select * from blog_post where user_id in (selectfriend_id from user_friend where user_id = :userId) 按日期排序

我能想到的 GAE 解决方案是:

  • 加载用户,循环浏览朋友列表并加载他们最新的博客文章。最后合并所有博文,找到最新的10篇博文
  • 在博客文章中列出所有将作者作为朋友的用户。这意味着简单的阅读,但在添加拥有大量博客文章的朋友时会导致配额超载。

我不相信这些解决方案中的任何一个都会扩展。

我确定其他人已经遇到了这个问题,但我已经搜索过、观看过 google io 视频、阅读过其他人的代码……我错过了什么?

4

4 回答 4

13

如果您查看您提供的 SQL 解决方案将如何执行,它将基本上是这样的:

  1. 获取当前用户的好友列表
  2. 对于列表中的每个用户,开始对最近的帖子进行索引扫描
  3. 合并第 2 步中的所有扫描,当您检索到足够的条目时停止

您可以在 App Engine 中自己执行完全相同的过程,方法是将 Query 实例用作迭代器并对它们进行合并连接。

你是对的,这不会很好地扩展到大量的朋友,但它遇到了与 SQL 实现完全相同的问题,它也没有掩饰它们:获取最新的 20 个(例如)条目的成本大约是O(n log n) 工作,其中 n 是朋友的数量。

于 2009-01-15T11:58:10.587 回答
7

Google io 演讲中涵盖了该主题: http ://code.google.com/events/io/sessions/BuildingScalableComplexApps.html

基本上谷歌团队建议使用列表属性和他们所谓的关系索引实体,可以在这里找到一个示例应用程序:http: //pubsub-test.appspot.com/

于 2009-06-25T11:06:54.863 回答
1

“加载用户,循环浏览朋友列表并加载他们最新的博客文章。”

这就是一个连接——嵌套循环。某些类型的连接是带有查找的循环。大多数查找只是循环;有些是哈希。

“最后合并所有博文,找到最新的10篇博文”

这是一个有限制的 ORDER BY。这就是数据库正在为您做的事情。

我不确定这有什么不可扩展的;无论如何,这就是数据库的作用。

于 2009-01-15T11:59:10.710 回答
0

这是一个来自http://pubsub-test.appspot.com/的 python 示例:

有人有java的吗?谢谢。

from google.appengine.ext import webapp

from google.appengine.ext import db

class Message(db.Model):
 body = db.TextProperty(required=True)
 sender = db.StringProperty(required=True)
 receiver_id = db.ListProperty(int)

class SlimMessage(db.Model):
 body = db.TextProperty(required=True)
 sender = db.StringProperty(required=True)

class MessageIndex(db.Model):  
 receiver_id = db.ListProperty(int)

class MainHandler(webapp.RequestHandler):

 def get(self):
  receiver_id = int(self.request.get('receiver_id', '1'))
  key_only = self.request.get('key_only').lower() == 'on'
  if receiver_id:
    if key_only:
      keys = db.GqlQuery(
          'SELECT __key__ FROM MessageIndex WHERE receiver_id = :1',
          receiver_id).fetch(10)
      messages.extend(db.get([k.parent() for k in keys]))
    else:
      messages.extend(Message.gql('WHERE receiver_id = :1',
                      receiver_id).fetch(10))
于 2009-11-23T22:54:57.357 回答