Как я могу лучше использовать фильтры в appengine, чтобы избавить меня от фильтрации, просматривая длинный список сущностей? - PullRequest
1 голос
/ 15 февраля 2012

следующий бит кода регулярно выполняется как cronjob и оказывается очень дорогим в вычислительном отношении! Основная проблема заключается в цикле for, и я думаю, что это можно сделать несколько более эффективным с помощью лучшей фильтрации, однако я не знаю, как это сделать.

free_membership_type = MembershipType.all().filter("membership_class =", "Free").filter("live =", True).get()
all_free_users = UserMembershipType.all().filter("membership_active =", True)
all_free_users = all_free_users.filter("membership_type =", free_membership_type).fetch(limit = 999999)
if all_free_users:
    for free_user in all_free_users:
        activation_status = ActivationStatus.all().filter("user = ", free_user.user).get()
        if activation_status and activation_status.activated:
            documents_left = WeeklyLimits.all().filter("user = ", free_user.user).get()
            if documents_left > 0:
                do something...

Модели, которые использует код:

class MembershipType(db.Model):
    membership_class = db.StringProperty()
    membership_code = db.StringProperty()
    live = db.BooleanProperty(default = False)

class UserMembershipType(db.Model):
    user = db.ReferenceProperty(UserModel)
    membership_type = db.ReferenceProperty(MembershipType)
    membership_active = db.BooleanProperty(default = False)

class ActivationStatus(db.Model):
    user = db.ReferenceProperty(UserModel) 
    activated = db.BooleanProperty(default = False)

class WeeklyLimits(db.Model):
    user = db.ReferenceProperty(UserModel) 
    membership_type = db.ReferenceProperty(MembershipType) 
    documents_left = db.IntegerProperty(default = 0)

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

Ответы [ 3 ]

2 голосов
/ 15 февраля 2012

Магия, которую вы, вероятно, ищете, это денормализация . Мне кажется, что все эти классы могут быть осмысленно объединены в одну модель:

class Membership(db.Model):
    user = db.ReferenceProperty(UserModel)
    membership_class = db.StringProperty()
    membership_code = db.StringProperty()
    live = db.BooleanProperty(default = False)
    membership_active = db.BooleanProperty(default = False)
    activated = db.BooleanProperty(default = False)
    documents_left = db.IntegerProperty(default = 0)

Затем вы можете использовать один запрос для выполнения всей вашей фильтрации.

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

Можете ли вы увидеть какие-либо недостатки в хранении всех этих полей в одной модели?

2 голосов
/ 15 февраля 2012

Вы можете улучшить это, храня данные ближе друг к другу в одной модели. Например, один тип сущности UserMembership может иметь все необходимые поля, и вы можете выполнить один запрос:

.filter("membership_type =", "FREE").filter("status =", "ACTIVE").filter("documentsLeft >", 0)

Для этого потребуется определить дополнительный индекс, но он будет работать намного, намного быстрее.

1 голос
/ 19 февраля 2012

Если вы хотите избежать денормализации ваших данных, как предложено в двух других ответах, вы можете также рассмотреть возможность использования новой службы SQL Google вместо обычного хранилища данных: http://googleappengine.blogspot.com/2011/10/google-cloud-sql-your-database-in-cloud.html

С SQL вы можете сделать всеэто в одном запросе, даже с отдельными объектами.

...