GAE文本搜索与二级排序

时间:2011-10-20 18:58:29

标签: python google-app-engine full-text-search

代替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)

2 个答案:

答案 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步中的每个记录。

将键转换为字符串也是完全没必要的 - 您可以将键添加到设置就好了。

但是,对于它的价值,我个人认为'或'搜索特别无用。我意识到你会先对所有条款进行排名,但不可避免地会出现一堆堆不相关的结果。您只需使用每个搜索词的相等过滤器进行一次查询即可进行“和”搜索。