代替GAE的全文搜索,我使用下面的解决方案返回一个排序的结果集,首先是关键字相关性,其次是按日期排序(尽管第二次排序可能是真的)。感觉有点笨重,我很关注大规模的性能,所以我正在寻找优化建议或完全不同的方法。
二次排序对我的用例很重要,因为给定的搜索可能会有相同相关性的多个结果(通过关键字匹配的数量来衡量),但是保留原始查询排序现在增加了很多复杂性。有什么想法吗?
第1步:获取与每个搜索字词匹配的键列表
results_key_list = []
search_terms = ['a','b','c'] #User's search query, split into a list of strings
#query each search term and add the results to a list
#yields a list of keys with frequency of occurance indicating relevance
for item in search_terms:
subquery = SomeEntity.all(keys_only=True)
subquery.filter('SearchIndex = ', item) #SearchIndex is a StringListProperty
#more filters...
subquery.order('-DateCreated')
for returned_item in subquery:
results_key_list.append(str(returned_item))
步骤2:按频率对列表进行分组,同时保持原始顺序
#return a dictionary of keys, with their frequency of occurrence
grouped_results = defaultdict(int)
for key in results_key_list:
grouped_results[key] += 1
sorted_results = []
known = set()
#creates an empty list for each match frequency
for i in range(len(search_terms)):
sorted_results.append([])
#using the original results ordering,
#construct an array of results grouped and ordered by descending frequency
for key in results_key_list:
if key in known: continue
frequency = grouped_results[key]
sorted_results[len(search_terms) - frequency].append(key)
known.add(key)
#combine into a single list
ordered_key_list = []
for l in sorted_results:
ordered_key_list.extend(l)
del ordered_key_list[:offset]
del ordered_key_list[limit:]
result = SomeEntity.get(ordered_key_list)
答案 0 :(得分:2)
search_terms = ['a','b','c'] #User's search query, split into a list of strings
您可以按照外观顺序累积按键 并且可以在一次通过中建立所有关键频率。 利用排序稳定性通过降低频率进行排序,然后按出现顺序进行排序:
keys_in_order_of_appearance = []
key_frequency = defaultdict(int)
for item in search_terms:
subquery = SomeEntity.all(keys_only=True)
subquery.filter('SearchIndex = ', item) #SearchIndex is a StringListProperty
#more filters...
subquery.order('-DateCreated')
for returned_item in subquery:
key = str(returned_item)
if key not in key_frequency:
key_order_of_appearance.append(key)
key_frequency[key] += 1
keys = keys_in_order_of_appearance[:] # order of appearance kept as secondary sort
keys.sort(key=key_frequency.__getitem__, reverse=True) # descending freq as primary sort
result = SomeEntity.get(ordered_key_list)
答案 1 :(得分:2)
在第1步中,您将迭代查询对象。这导致返回每20个对象一次获取RPC,这在时间上是低效的。相反,在Query对象上调用fetch(n)
,其中n
是要返回的最大结果数 - 这只会生成一个RPC。它还有限制搜索结果的数量 - 现在,如果我搜索“我”,您的应用程序将几乎处理第1步中的每个记录。
将键转换为字符串也是完全没必要的 - 您可以将键添加到设置就好了。
但是,对于它的价值,我个人认为'或'搜索特别无用。我意识到你会先对所有条款进行排名,但不可避免地会出现一堆堆不相关的结果。您只需使用每个搜索词的相等过滤器进行一次查询即可进行“和”搜索。