我正在尝试创建一个查询模型中多个属性的搜索功能。为了使事情变得更加困难,我希望能够在列表理解中使用多个术语,然后根据更准确的结果进行排序。
例如,如果搜索条件为['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]
答案 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)]
我希望这可以解释这一点。但是,这个算法只适用于简单的文本。您可能必须根据电子项目更改算法,例如,如果您的网站依赖于它。有时您可能需要查看对象本身的属性。这应该是一个很好的首发。