GAE - Как жить без объединений? - PullRequest
13 голосов
/ 15 января 2009

Пример задачи:

Объекты:

  • Пользователь содержит имя и список друзей (Отзывы пользователей)
  • Запись блога содержит заголовок, содержание, дату и автора (пользователя)

Требования:

Мне нужна страница, которая отображает заголовок и ссылку на блог последних 10 сообщений друга пользователя. Я также хотел бы иметь возможность продолжать просматривать старые записи.

Решение SQL:

Так что в sql land это будет что-то вроде:

select * from blog_post where user_id in (select friend_id from user_friend where user_id = :userId) order by date

Решения GAE, о которых я могу думать:

  • Загрузить пользователя, просмотреть список друзей и загрузить их последние сообщения в блоге. Наконец, объедините все записи в блоге, чтобы найти последние 10 записей в блоге
  • В сообщении блога есть список всех пользователей, у которых писатель является другом. Это будет означать простое чтение, но приведет к перегрузке квоты при добавлении друга, у которого много сообщений в блоге.

Я не верю, что какое-либо из этих решений будет масштабироваться.

Я уверен, что другие столкнулись с этой проблемой, но я искал, смотрел видео Google io, читал код другого ... Что я пропустил?

Ответы [ 4 ]

13 голосов
/ 15 января 2009

Если вы посмотрите, как будет выполняться предоставленное вами решение SQL, оно будет выглядеть примерно так:

  1. Получить список друзей для текущего пользователя
  2. Для каждого пользователя в списке запустить сканирование индекса по последним сообщениям
  3. Объединить все сканы, начиная с шага 2, останавливаясь, когда вы получили достаточно записей

Вы можете выполнить точно такую ​​же процедуру самостоятельно в App Engine, используя экземпляры Query в качестве итераторов и выполняя объединение с ними.

Вы правы, что это не будет хорошо масштабироваться для большого количества друзей, но страдает от тех же проблем, что и реализация SQL, но также не скрывает их: выборка последних 20 (например) Записи стоят примерно O (n log n) работы, где n - количество друзей.

7 голосов
/ 25 июня 2009

Эта тема освещена в докладе Google io: http://code.google.com/events/io/sessions/BuildingScalableComplexApps.html

Как правило, команда Google предлагает использовать свойства списка и то, что они называют сущностями реляционного индекса, пример приложения можно найти здесь: http://pubsub -test.appspot.com /

1 голос
/ 15 января 2009

"Загрузить пользователя, просмотреть список друзей и загрузить их последние записи в блоге."

Вот и все объединение - вложенные циклы. Некоторые виды соединений - это циклы с поисками. Большинство поисков - просто циклы; некоторые хеши.

«Наконец, объедините все записи в блоге, чтобы найти последние 10 записей в блоге»

Это ORDER BY с ПРЕДЕЛОМ. Вот что база данных делает для вас.

Я не уверен, что не масштабируется по этому поводу; это то, что база данных делает в любом случае.

0 голосов
/ 24 ноября 2009

Вот пример на python, блестящем от http://pubsub -test.appspot.com / :

У кого-нибудь есть один для 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))
...