2015-03-31 2 views
0

Я пытаюсь выбрать 3 последних опубликованных элемента с любыми тегами, похожими на текущий элемент (и некоторые другие фильтры тоже) Не могу найти эффективный способ сделать это, есть много «элементов» в БД.django taggit Similar_objects очень медленный запрос

from taggit_autosuggest.managers import TaggableManager 

class Item(models.Model): 
    publish_date = DateField() 
    tags = TaggableManager() 
    sites = ManyToManyField(Site) 

def my_view(): 
    ... 
    current_item = #get current item 
    related_items = Item.active_objects.filter(
     sites=current_site, 
     id__in=[x.id for x in current_item.tags.similar_objects()] 
     ).order_by('-publish_date')[:3] 
    ... 

Но это вызывает довольно большие проблемы с производительностью из метода similar_objects(). экспоненциально хуже, чем больше ярлыков current_item имеет

# Query_time: 20.613503 Lock_time: 0.000182 Rows_sent: 83 Rows_examined: 7566504 
SELECT `taggit_taggeditem`.`content_type_id`, `taggit_taggeditem`.`object_id`, COUNT(`taggit_taggeditem`.`id`) AS `n` FROM `taggit_taggeditem` WHERE (NOT (`taggit_taggeditem`.`object_id` = 205636 AND `taggit_taggeditem`.`content_type_id` 
= 11) AND (`taggit_taggeditem`.`tag_id`) IN (SELECT DISTINCT `taggit_tag`.`id` FROM `taggit_tag` INNER JOIN `taggit_taggeditem` ON (`taggit_tag`.`id` = `taggit_taggeditem`.`tag_id`) WHERE (`taggit_taggeditem`.`object_id` = 205636 AND 
`taggit_taggeditem`.`content_type_id` = 11))) GROUP BY `taggit_taggeditem`.`content_type_id`, `taggit_taggeditem`.`object_id` ORDER BY `n` DESC; 

Я также не попытался с помощью метода подобных объектов

related_items = Item.active_objects.filter(
    sites=current_site, 
    tags__in=current_item.tags.all()).exclude(slug=slug).order_by('-publish_date').distinct()[:3] 
    context['tagged'] = tags.order_by('-publish_date').distinct()[:3] 

, который был последовательно хуже (некоторые запросы до к 120s, дрянь)

Что такое «хороший» способ сделать это ?!

ответ

5

Моя гипотеза заключалась в том, что получение тегов и использование отношения tag-> item было бы более эффективным, чем поиск всех элементов. Итак, мы создаем запрос всех TaggedItem, получаем идентификатор всех объектов, а затем выполняем наш фильтр.

from taggit.models import TaggedItem 
related_items = TaggedItem.objects.none() 
for tag in current_item.tags.all(): 
    #build queryset of all TaggedItems 
    related_items |= tag.taggit_taggeditem_items.all() 

#TaggedItem doesn't have a direct link to the object, have to grab ids 
ids = related_items.values_list('object_id', flat=True) 
return Item.objects.filter(id__in=ids, sites=current_site).exclude(id=item.id).order_by('-publish_date')[:3] 
0

Я думаю, что вы могли бы сделать это следующим образом:

related_items = current_item.tags.similar_objects().filter(
    sites=current_site, 
).order_by('-publish_date')[:3] 

Хотя я думаю, что вы должны были бы включать в себя логику, которая стоит за active_objects снова в этом фильтре.

+0

Да, но все дело в том, чтобы избежать метода similar_objects(). Поскольку это причина запроса выше, что экспоненциально плохо, тем больше тегов текущая история имеет – straykiwi

+0

Этот запрос, который вы дали, имеет '' 'like_objects()' '' вызов, который используется вместе с '' '__in'''. Если '' 'similar_objects()' '' возвращает много объектов, которые '' 'in''' будут выполнять ужасно. То, что я предложил, заключается в использовании объединений, а не '' 'in'''. Попробуйте и посмотрите, как это работает. – schillingt

+0

http://django-taggit.readthedocs.org/ru/latest/api.html#TaggableManager.similar_objects Причина в том, что similar_objects возвращает список, а не набор запросов. Если вы посмотрите на реализацию, ее довольно плохо. Я придумал решение, которое работает намного лучше, его не произведение искусства, хотя я не буду его принимать, если что-то лучше появится – straykiwi