在Django中加权搜索

问题描述:

我有三个输入从窗体进来。它们是name,neighborhoodstags。邻里和标签是多选框字符串列表。这是我当前的查询:在Django中加权搜索

q = Restaurant.objects.filter(name__icontains=name) 
q = q.filter(neighborhoods__name__in=neighborhoods) 
for tag in tags: 
    q = q.filter(tags__name=tag) 
q = q.order_by('name').distinct() 

当前提取所有餐馆的所有标签和所有邻里。我在进行加权搜索时遇到了一些麻烦。基本上,对于每个匹配的标签和邻域,我想在权重列中添加一个点。然后我会按重量排序,即使一家餐厅只匹配三个标签中的两个,它仍会显示(其重量为2)。这是为了防止0结果发生并显示最接近的结果。另外,我想要求选择一家餐厅至少需要1分。

我想在SQL它会是这样的:

SELECT *, 
    (SELECT COUNT(1) 
    FROM tags t 
    WHERE t.name IN (%s) 
    ) AS weight 
FROM restaurants 
WHERE weight > 0 
ORDER BY weight DESC 

你想用annotate()

from django.db.models import Count 
q = Restaurant.objects.filter(name__icontains=name) 
q = q.filter(neighborhoods__name__in=neighborhoods) 
for tag in tags: 
    q = q.filter(tags__name=tag) 
q = q.order_by('name').annotate(num_tags=Count('tags__name')).filter(num_tags__gte=2) 

更新

看代码,我再次看到,不幸的是它的过滤掉,以便只与所有标签匹配。我想,只是这种变化应该工作:

摆脱:

q = q.filter(tags__name__in=tags) 

那它放在餐厅被加上的至少一个所有查询匹配方式:

for tag in tags: 
    q = q.filter(tags__name=tag) 

与更换请求的标签。 annotatefilter后来负责确保它匹配至少2.

+0

在这里等一下......这只是计算餐厅的标签数量,而不是与标签列表匹配的标签数量。我需要类似'.annotate(num_tags = Count('tags__name__in'= tags))' – 2010-09-20 17:06:14

+1

不,q = q.filter(tags__name__in = tags)代码限制行只包含匹配的标签。 '.annotate(Count('tags__name'))'将记录除了标记记录以外的所有内容分组。如果您搜索5个标签,则有3个餐厅,A,B和C;和A匹配1个标签,B 3和C 4,然后在注释行(A:num_tags 1,B:num_tags 3,C:num_tags 4)和'filter()'删除A之后,离开B和C.告诉你'.annotate(num_tags = Count('tags__name__in'= tags))'会抛出一个错误。 “Count”的参数只是字段名称,而不是过滤器中的子句。 – 2010-09-20 18:43:47

+0

好的,我的坏。非常感谢! – 2010-09-20 20:03:09