使用多个术语和Q过滤器对reduce查询进行排序

时间:2015-06-05 04:01:14

标签: python django python-2.7 django-queryset django-q

我正在尝试创建一个查询模型中多个属性的搜索功能。为了使事情变得更加困难,我希望能够在列表理解中使用多个术语,然后根据更准确的结果进行排序。

例如,如果搜索条件为['green', 'shoe']并且我有一个名为'green shoe'的对象,我希望这是我的结果中的第一项,后跟'black shoe'或{{1 }}

到目前为止,我从查询参数中提取搜索词,然后运行Q查询。

'green pants'

这会返回def get_queryset(self): search_terms = self.request.GET.getlist('search', None) terms = [] x = [terms.extend(term.lower().replace('/', '').split(" ")) for term in search_terms] # x is useless, but it is just better to look at. results = reduce(operator.or_, (Item.objects.filter(Q(name__icontains=term) | Q(description__icontains=term) | Q(option__name__icontains=term)) for term in terms)) return results ,这是乱序的,但它是所有匹配的结果。

我意识到我可以让它不会将搜索词分成多个术语,只会得到一个结果但是我不会得到其他相似的东西。

感谢您寻找

修改1

所以在第一个回答后我开始玩它。现在这会产生我想要的结果,但我觉得由于将查询集添加到列表中可能会很糟糕。让我知道你的想法:

['black shoe', 'green pants', 'green shoe']

def get_queryset(self): search_terms = self.request.GET.getlist('search', None) if not search_terms or '' in search_terms or ' ' in search_terms: return [] terms = [term.lower().replace('/', '').split(" ") for term in search_terms][0] results = reduce(operator.or_, (Item.objects.filter (Q(name__icontains=term) | Q(description__icontains=term) | Q(option__name__icontains=term)) for term in terms)) # creating a list so I can index later # Couldn't find an easy way to index on a generator/queryset results = list(results) # Using enumerate so I can get the index, storing index at end of list for future reference # Concats the item name and the item description into one list, using that for the items weight in the result results_split = [t.name.lower().split() + t.description.lower().split() + list((x,)) for x, t in enumerate(results)] query_with_weights = [(x, len(search_terms[0].split()) - search_terms[0].split().index(x)) for x in terms] get_weight = lambda x: ([weight for y, weight in query_with_weights if y==x] or [0])[0] sorted_results = sorted([(l, sum([(get_weight(m)) for m in l])) for l in results_split], key=lambda lst: lst[1], reverse=True) # Building the final list based off the sorted list and the index of the items. final_sorted = [results[result[0][-1]] for result in sorted_results] print results_split print query_with_weights print final_sorted return final_sorted 的查询会打印出来:

[red, shoes, pants]

1 个答案:

答案 0 :(得分:2)

这不完全是QuerySet问题。

这需要一个单独的算法来决定您创建的结果集的顺序。我会写一个新的算法来决定排序 - 可能是整个algos数组,因为你的结果将取决于查询本身的category

现在我可以考虑为结果集中的每个结果添加权重,根据一些参数决定它与查询完成的接近程度。

在您的情况下,您的参数如下:

  • 匹配了多少个单词?
  • 首先出现的字词应该是最高优先级
  • 任何完全匹配的查询都应具有最高优先级
  • 查询远端的字词应具有最低优先级

无论如何,这是一个开头的想法,我相信你可能会更复杂。

所以这是创建排序的代码:

query = 'green shoe'
query_with_weights = [(x, len(query.split()) - query.split().index(x)) for x in query.split()]
results = ['black pants', 'green pants', 'green shoe']
results_split = [res.split() for res in results]

get_weight = lambda x: ([weight for y, weight in query_with_weights if y==x] or [0])[0]
sorted_results = sorted([ (l, sum([( get_weight(m)) for m in l])) for l in results_split], key = lambda lst: lst[1], reverse=True)
print('sorted_results={}'.format(sorted_results))

尝试此操作后,您将获得以下结果:

  

sorted_results = [(['green','shoe'],3),(['green','pants'],2),   (['black','裤子'],0)]

我希望这可以解释这一点。但是,这个算法只适用于简单的文本。您可能必须根据电子项目更改算法,例如,如果您的网站依赖于它。有时您可能需要查看对象本身的属性。这应该是一个很好的首发。

相关问题