Разбиение на страницы и множественные реляционные индексы сущностей с AppEngine - PullRequest
0 голосов
/ 24 октября 2010

Это общий вопрос о разбиении на страницы с моделями, содержащими несколько индексов сущностей.Это проще сделать с примером, поэтому давайте рассмотрим пример, который Бретт Слаткин представил в своем видео (http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html).

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

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

Теперь мне интересно создавать фильтры для нескольких полей, скажем, сообщений, опубликованных в определенном временном окне. Например,

select * from Message where pubished > some_date and expires < some_other_date

Поскольку GAE не разрешает фильтры неравенствадля нескольких полей мы должны разбить модели на дополнительные индексы, поэтому теперь у нас есть индекс для опубликованных полей и полей с истекшим сроком действия, что дает нам следующие модели (с экземпляром Message, являющимся родителем экземпляров MessagePublishedIndex и MessageExpiryIndex):

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

class MessagePublishedIndex(db.Model):
    published = db.DateTimeProperty()

class MessageExpiryIndex(db.Model):
    expires = db.DateTimeProperty()

и следующие запросы key_only:

publish_keys = MessagePublishedIndex.all(key_only = True).filter("published >", some_date)
expire_keys = MessageExpiryIndex.all(key_only = True).filter("expires <", some_other_date)

msgs_by_pubdate = db.get([k.parent() for k in publish_keys])
msgs_by_expiry  = db.get([k.parent() for k in expire_keys])

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

Это кажется довольно расточительным. Есть ли более простой способ сделать это?Также эта проблема усугубляется, если поле в индексе является ListProperty, потому что запросы key_only не могут иметь фильтры «IN».И что еще хуже, если я хочу разбить на страницы (то есть "считать" результаты из "смещения"), я должен вручную отбросить первые результаты "смещения", а затем сделать пересечение.Конечно, должен быть более легкий (и более умный) способ сделать это.Есть идеи?Достаточно плохо, что GAE не разрешает фильтры неравенства для нескольких полей (хотя и из соображений эффективности), но вручную выполнять все зигзаги кажется довольно неэффективным (не говоря уже о работе с процессором и ограничением по времени).

1 Ответ

0 голосов
/ 23 марта 2011

В вашем сценарии я бы создал одну сущность реляционного индекса

class MessageIndex(db.Model):
    keywords = db.StringListProperty();

, где каждый элемент в списке ключевых слов будет иметь формат =

, например:words = ["опубликовано = 2011-03-24", "истекает = 2011-03-25"]

Вам необходимо выполнить сериализацию / десериализацию самостоятельно, чтобы получить значение свойства.Кроме того, вы все еще можете хранить значения свойств в модели сообщений только для избыточности.Однако этот подход не работает с запросом диапазона.(Я не проверял, но вы, вероятно, можете использовать запрос с префиксом для фальсификации запроса диапазона: u "опубликовано = 2010" + u "\ ufffd", здесь более подробно )

всегда было проблемой, чтобы оптимизировать для GAE.Но это весело и полезно.

...