您可以采取一些措施来提高顺序搜索的性能,但真正的提升将来自索引标记。
set.difference
使用not local_q_set.difference(s_tokens) 而不是将交集与原始集合进行比较可能会更快。
正则表达式过滤器
如果您的句子很长,使用正则表达式可以通过在检查它们与标记集之前将潜在标记从句子中隔离出来来提高速度:
import re
tokens = re.compile("|".join(local_q_set))
tokenCount = len(local_q_set)
for s_index, s in enumerate(sentences):
s_tokens = tokens.findall(s)
if len(s_tokens) < tokenCount or local_q_set.difference(s.split()):
continue
q_results.append(s_index)
使用 in 运算符过滤
您还可以使用简单的in 运算符来检查是否存在令牌而不是正则表达式(当查询中的令牌很少时,这应该会更快):
result = []
tokenSet = set(queryTokens)
for index, sentence in enumerate(sentences):
if any( token not in sentence for token in queryTokens) \
or tokenSet.difference(sentence.split()):
continue
result.append(index)
缓存句子词集
当对同一个句子列表进行多次查询时,为了改进顺序搜索,您可以构建与句子对应的词集缓存。这将消除在通过句子查找匹配项时解析句子的工作。
cachedWords = []
queryTokens = ["happy","apple"]
queryTokenSet = set(queryTokens)
if not cachedWords:
cachedWords = [ set(sentence.split()) for sentence in sentences ]
result = [ index for index,words in enumerate(cachedWords) if not queryTokenSet.difference(words) ]
令牌索引
如果您要针对同一个句子列表执行许多查询,则在标记和句子索引之间创建映射会更有效。您可以使用字典来完成,然后通过与查询标记的句子索引相交来直接获取查询结果:
tokenIndexes = dict()
for index,sentence in enumerate(sentences):
for token in sentence.lower().split():
tokenIndexes.setdefault(token,[]).append(index)
def tokenSet(token): return set(tokenIndexes.get(token,[]))
queryTokens = ["happy","apple"]
from functools import reduce
result = reduce(set.intersection , (tokenSet(token) for token in queryTokens) )
这将使您能够使用集合运算符经济地实现复杂的查询。例如:
import re
querySring = " happy & ( apple | orange | banana ) "
result = eval(re.sub("(\w+)",r"tokenSet('\1')", querySring))
# re.sub(...) transforms the query string into " tokenSet('happy') & ( tokenSet('apple') | tokenSet('orange') | tokenSet('banana') ) "
性能测试:
我做了一些性能测试(在 80,000 个句子中找到两个标记):
original algorithm: 105 ms 1x
set.difference: 88 ms 1.2x
regular expression: 60 ms 1.8x
"in" operator: 43 ms 2.4x
caching word sets: 23 ms 4.6x (excluding 187ms to build cache)
token indexing: 0.0075 ms 14000x (excluding 238ms to build tokenIndexes)
因此,如果您要对同一个句子执行多个查询,使用令牌索引,一旦构建了 tokenIndexes 字典,您将获得快 14000 倍的响应。