使用Django的Postgres全文搜索匹配一个或多个关键字

时间:2017-04-24 03:27:17

标签: django postgresql full-text-search

如果我在一个网站上搜索多个关键字(并且没有引号) - 例如红色汽车 - 我的期望是包含“红色汽车”的项目应该是第一个,然后是包含两个关键字(但非按顺序)的项目,后跟包含其中一个关键字的项目。 (我相信这是Lucene系统中的默认行为,但是自从我使用它们已经有一段时间了,所以不能肯定地说。)

我希望Postgres全文搜索会自动执行此操作,但我的早期测试显示情况并非如此:

## ASSUME: items in database: <blue car>, <green car>, <red truck>

keywords = "red car"
items = ForSaleItem.objects.filter(name__search=keywords)

## RESULT: items is empty/None, whereas it should have each of 
##         the items since one keyword matches.

我看到的黑客是使用Django的析取运算符,但我希望有一些不那么黑的东西。我也很确定这个黑客不会把精确的匹配放在列表的顶部。这是黑客:

from django.db.models import Q
keyword_query = Q()
for keyword in keywords.split(' '):
    keyword_query.add(Q(name__search=keyword), Q.OR)
items = ForSaleItem.objects.filter(keyword_query)

是否有一些我缺少的设置/ API(或者在postgres方面可实现的东西)获得了我期望的功能?

2 个答案:

答案 0 :(得分:2)

感谢@Dharshan指出我正确的方向。正如他或她所指出的,SearchQuery对象的分离将允许匹配任一关键字。此外,要将包含两个关键字的项目放在列表顶部 -  如Django full text search docs中所述 - SearchRank类可以按如下方式使用:

vector = SearchVector('name')
query = SearchQuery('red') | SearchQuery('car')
items = ForSaleItem.objects.annotate(rank=SearchRank(vector, query)).order_by('-rank')

答案 1 :(得分:0)

items = ForSaleItem.objects.filter(name__contains=keywords)