Эффективность агрегирования и аннотирования против сигналов
Я хочу подсчитать количество вкладов, сделанных пользователем на моем сайте, чтобы я мог оценить их на сайте. Мне удалось написать красивый код, который делает именно это, но для каждого пользователя.
Поскольку пользователь получает разные суммы баллов для разных полей, он проверяет определенные поля в модели и определяет, введет ли пользователь значение в них. Затем он умножает эти значения на их веса, чтобы получить общую оценку.
Ничто не говорит это лучше, чем немного кода:
class UserContribCounter(object):
"""Can count the number of points a user got for his contributions"""
weight_dict = {'poster':2, 'title':1}
def __init__(self, user):
if isinstance(user, User):
self.user = user
else:
raise Exception('Not a valid user instance.')
def set_contrib_points(self):
"""Some dark magic counts the number of times a certain field was filled out"""
self.unweighted = Movie.objects.filter(user = self.user).aggregate(poster=Count('poster'),title=Count('title'))
def get_contrib_points(self):
"""Multiplies the number of times a field was filled out with their weights to calculate the total number of points"""
try:
self.unweighted
except AttributeError:
self.set_contrib_points()
return sum([self.weight_dict[key] * value for key, value in self.unweighted.items()])
Я также хочу показать топ-10, поэтому мне нужно получить топ-10 пользователей. Это означает, что мне придется либо написать сложную агрегацию, которую в данный момент я не могу выполнить, либо я мог бы использовать сигнал следующим образом:
Когда модель будет сохранена, поймайте сигнал post_save. Затем используйте мой существующий класс, чтобы пересчитать баллы для пользователя и сохранить его в профиле пользователя. Таким образом, я могу сортировать пользователей по значению в их профиле, что тривиально.
Вопрос в том, что будет более эффективным: делать пересчет каждый раз при сохранении модели или использовать довольно сложную функцию агрегирования. Я знаю, что это будет зависеть от многих вещей, но я уверен, что с концептуальной точки зрения, должны быть причины выбирать одно из другого. Обратите внимание, что некоторые поля, которые я проверю в совокупности, также будут реляционными, поэтому я не уверен, как это повлияет на производительность.
Заранее спасибо,
tBuLi
1 ответ
Я бы сказал, что это зависит от того, как часто меняется ваша модель и насколько точной и актуальной должна быть ваша топ-10. Для чего это стоит, вы можете кэшировать топ-10 на час или даже день. С другой стороны, если вам потребуется выполнить сложное упорядочение или обработку, которые не охватываются агрегатами django, вы извлечете выгоду из денормализации.
И в конце концов, все сводится к тому, чтобы на самом деле определить узкое место в реальном мире. Сделайте сначала самое маленькое из возможных, серьезно.