Высоко масштабируемые теги в Google App Engine (Python) - PullRequest
5 голосов
/ 25 ноября 2010

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

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 голос
/ 29 ноября 2010

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

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

0 голосов
/ 25 ноября 2010

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

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 сообщений, просто объедините их. При выводе сообщений по тегу (в порядке пост-даты) вам нужно получить только несколько групп.

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

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

...