2015-03-31 209 views
0

我想選擇3個最近發佈的項目,與任何標籤類似的當前項目(和其他一些過濾器太) 找不到有效的方式來做到這一點,有數據庫中有很多'item'。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] 

這是一貫糟糕的(一些查詢高達120秒,呸)

什麼是「好」的方法來做到這一點?!

回答

5

我的假設是獲取標籤,並使用標籤 - >項目關係比搜索所有項目更有效。 所以我們構建一個所有TaggedItem的查詢集,獲取所有對象的ID,然後執行我們的過濾器。

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 2015-04-01 03:36:52

+0

您提供的查詢具有與''__in'''一起使用的similar_objects()調用。如果''''''''''''''''''''''''''會返回很多'''''''''將要執行的對象。我建議使用連接而不是''''''''。試試看看它是如何工作的。 – schillingt 2015-04-01 11:28:06

+0

http://django-taggit.readthedocs.org/en/latest/api.html#TaggableManager.similar_objects 原因是因爲similar_objects返回的不是查詢集列表。如果你看一下實現,那很糟糕。 我想出了一個更好的解決方案,但它不是一件藝術品,所以我不會接受它,以防萬一有更好的東西出現 – straykiwi 2015-04-01 20:24:53