Задать вопрос

Как оптимизировать/ускорить сортировку QuerySet?

Доброго времени суток!
Имеется 2 модели - кастомная User и Interest. У каждого пользователя есть определенное количество интересов. Когда пользователь переходит на конкретную страницу, ему предлагается связаться с другими пользователями, с которыми у него наибольшее количество общих интересов.
class Interest(models.Model):
        name = models.CharField(max_length=50, unique=True)
        users = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                       related_name="interests", blank=True)

Для получения и сортировки используем след. метод:
def suggested_people(user):
        queryset = User.objects.custom_filter(is_verified=True).order_by('-date_joined')
        users_sorted = sorted(queryset, key=lambda x: x.get_common_interest(user).count(), reverse=True)
        return users_sorted

Метод экземпляра класса User:
def get_common_interest(self, user):
        """ Return a list of string with the interests and the total number remaining """
        your_interests = user.interests.values_list('pk', flat=True)
        return self.interests.filter(pk__in=your_interests)

Проблема в том, что спискок полученных объектов сортируется очень медленно (для 1000 пользователей около 8с). Какие есть возможные способы решения данной проблемы? Буду благодарен за любой совет!
  • Вопрос задан
  • 470 просмотров
Подписаться 3 Оценить Комментировать
Решения вопроса 1
@aphex Автор вопроса
Решение:
from django.db.models import Count

interests_ids = u.interests.values_list('id', flat=True) # select ids of incoming user interests
suggestions = User.objects
                  .exclude(id=u.id) # exclude current user
                  .filter(is_verified=True) # filter only verified users
                  .filter(interests__id__in=interests_ids) # select users based on common interests
                  .annotate(interests_count=Count('interests')) # count numbers of interests for each user after filtering
                  .order_by('-interests_count') # order users by max common interests
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
suguby
@suguby
программист, python, django, mysql, git, hg, linux
Ну вы на каждого узера делает подзапрос - дико медленно. Посмотреть все запросы к БД можно с дебаг тулбара habrahabr.ru/post/50221 (увидите МНОГО интересного)
а что бы не тянуть в подзапросах используйте prefetch_related
queryset = User.objects.custom_filter(is_verified=True).prefetch_related('interects').order_by('-date_joined')
Ответ написан
Комментировать
iMeath
@iMeath
Python Developer
Можете выбирать только нужные вам данные. Существенно ускорит выборку

queryset = User.objects.custom_filter(is_verified=True).values('name', 'any-field').order_by('-date_joined')


Очень рекомендую читануть статью на хабре

Ко всему прочему не забывайте кешировать
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы