Высоко масштабируемые теги в Google App Engine (Python)

У меня много (например) постов, помеченных одним или несколькими тегами. Сообщение может быть создано или удалено, а также пользователь может сделать запрос поиска для одного или нескольких тегов (в сочетании с логическим И). Первая идея, которая пришла мне в голову, была простая модель

class Post(db.Model):
  #blahblah
  tags = db.StringListProperty()

Реализация операций создания и удаления очевидна. Поиск более сложный. Для поиска N тегов он будет выполнять N GQL-запросов, таких как "SELECT * FROM Post WHERE tags =:1", и объединит результаты с помощью курсоров, и он будет иметь ужасную производительность.

Вторая идея - разделить теги в разных сущностях.

class Post(db.Model):
    #blahblah
    tags = db.ListProperty(db.Key) # For fast access

class Tag(db.Model):
    name = db.StringProperty(name="key")
    posts = db.ListProperty(db.Key) # List of posts that marked with tag

Он берет теги из db по ключу (намного быстрее, чем GQL) и объединяет их в памяти, я думаю, что эта реализация имеет лучшую производительность, чем первая, но очень часто используемые теги могут превышать максимальный размер, который допускается для одного объекта хранилища данных, И есть еще одна проблема: хранилище данных может изменить один единственный объект только ~1/ сек, поэтому для часто используемых тегов у нас также есть узкое место с задержкой изменения.

Какие-либо предложения?

2 ответа

Для дальнейшего опроса Ника. Если это логическое И с использованием нескольких тегов в запросе. Использовать теги = тег1 и теги = тег2 ... установить членство в одном запросе - одна из ярких функций хранилища данных. Вы можете достичь своего результата одним запросом.

http://code.google.com/appengine/docs/python/datastore/queriesandindexes.html

Вероятно, возможное решение состоит в том, чтобы взять ваш второй пример и изменить его таким образом, чтобы обеспечить эффективные запросы на больших наборах. На ум приходит один способ - использовать несколько объектов базы данных для одного тега и сгруппировать их так, чтобы вам редко приходилось получать больше нескольких групп. Если порядок сортировки по умолчанию (хорошо, давайте просто назовем его единственно разрешенным) по дате публикации, то заполните группы тегов в этом порядке.

class Tag(db.Model):
    name = db.StringProperty(name="key")
    posts = db.ListProperty(db.Key) # List of posts that marked with tag
    firstpost = db.DateTimeProperty()

При добавлении или удалении тегов в группу проверьте, сколько сообщений в этой группе. Если добавляемый вами пост приведет к тому, что пост содержит более, скажем, 100 сообщений, разбейте его на две группы тегов. Если вы удаляете сообщение, чтобы в группе было менее 50 сообщений, украдите несколько сообщений из предыдущей или следующей группы. Если в одной из смежных групп также есть 50 сообщений, просто объедините их. При выводе сообщений по тегу (в порядке пост-даты) вам нужно всего лишь несколько групп.

Это на самом деле не решает проблему тегов с высоким спросом.

Думая об этом, было бы хорошо для вставок быть немного более умозрительным. Получить последние записи группы тегов, объединить их и разместить новую группу тегов. Задержка в транзакциях может на самом деле не быть реальной проблемой.

Другие вопросы по тегам