Подтвердить что ты не робот

Как бы вы создали хранилище данных AppEngine для социального сайта, такого как Twitter?

Мне интересно, как лучше всего разработать социальное приложение, в котором участники будут выполнять действия и выполнять другие действия с помощью Google AppEngine.

Чтобы быть более конкретным, предположим, что мы имеем эти сущности:

  • Пользователи, у кого есть друзья
  • Действия, которые представляют действия, сделанные пользователями (например, каждое из них имеет строковое сообщение и ReferenceProperty для своего владельца или может использовать родительскую ассоциацию с помощью ключа appengine)

Жесткая часть следит за действиями ваших друзей, что означает объединение последних действий со всех ваших друзей. Обычно это будет объединение между таблицей "Деятельность" и списком друзей, но это не жизнеспособный дизайн приложения, так как нет имитации соединения, для этого требуется запуск N запросов (где N - количество друзей), а затем слияние в памяти - очень дорогой и, вероятно, превысит срок подачи запроса...)

В настоящее время я собираюсь реализовать это, используя очереди входящих сообщений, когда создание нового Activity будет запускать фоновый процесс, который поместит новый ключ активности в "входящие" для каждого следующего пользователя:

  • Получение "Все пользователи, которые следуют за X" - это возможный запрос appengine
  • Не очень дорогой пакетный ввод в новый объект "Входящие", который в основном хранит кортежи (Пользователь, активность).

Я буду рад услышать мысль об этом дизайне или альтернативных предложениях и т.д.

4b9b3361

Ответ 1

Взгляните на Создание масштабируемых, сложных приложений в App Engine (pdf), увлекательный разговор, поставленный в Google I/O от Бретта Слаткина. Он решает проблему создания масштабируемой службы обмена сообщениями, такой как Twitter.

Здесь его решение использует свойство списка:

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

class MessageIndex(db.Model):
    #parent = a message
    receivers = db.StringListProperty()

indexes = MessageIndex.all(keys_only = True).filter('receivers = ', user_id)
keys = [k.parent() for k in indexes)
messages = db.get(keys)

Этот ключевой запрос находит индексы сообщений с приемником, равным указанному вами, без десериализации и сериализации списка получателей. Затем вы используете эти индексы для получения только тех сообщений, которые вы хотите.

Здесь неправильный путь:

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

messages = Message.all().filter('receivers =', user_id)

Это неэффективно, потому что запросы должны распаковывать все результаты, возвращаемые вашим запросом. Поэтому, если вы вернули 100 сообщений с 1000 пользователями в каждом списке получателей, вам придется десериализовать значения свойств списка 100 000 (100 x 1000). Слишком дорого стоит время ожидания хранилища и процессор.

Сначала я был полностью смущен всем этим, поэтому я написал короткий учебник

Ответ 2

Я не знаю, является ли это лучшим дизайном для социального приложения, но jaiku был портирован в App Engine оригинальным создателем, когда компания была приобретена Google, поэтому она должна быть разумной.

Смотрите раздел Актеры и тигры и медведи, Oh My! в design_funument.txt. Объекты определены в common/models.py, и запросы находятся в common/api.py.

Ответ 3

Я думаю, что теперь это можно решить с помощью новых проекционных запросов в NDB.

class Message(ndb.Model):
    sender = ndb.StringProperty()
    receivers = ndb.StringProperty(repeated=True)
    body = ndb.TextProperty()

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])

Теперь вам не нужно иметь дело с дорогостоящей стоимостью десериализации свойства списка.

Ответ 4

Роберт, о вашем предлагаемом решении:

messages = Message.query(Message.receivers == user_id).fetch(projection=[Message.body])

Я думаю, что "тело" ndb.TextProperty не может использоваться с проекциями, потому что не индексируется. Проекции поддерживают только индексированные свойства. Допустимым решением было бы поддерживать 2 таблицы: Message и MessageIndex.