项目中有如下需求,给定一个关键词库(规模不定,从几百到几千不等),需要在一句话或者一段内容中快速找出关键词,如果有任何一个关键词命中就可以直接返回。
1. 简单的方法就是依次判断每个词是否存在于给定内容中:
def filter(content):
for filter_word in filter_words:
if filter_word in content:
return True
return False
2. 可以使用trie树类似单字索引的方式来加速查找,使用trie查找关键词。
trie树结果上是一颗前缀树,某个节点的所有子孙都拥有相同的前缀,从根节点到叶子节点的一条路径可以认为是一个关键词。
#!/usr/bin/env python
#coding: utf-8
#author: wenhui
import os
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import json
class Trie(object):
def __init__(self,logger=None,rfile=None):
self.data = {'ref':{}}
if logger:self.logger = logger
if rfile:
self.load(rfile)
self.max_word_size = 0
self.word_num = 0
def add(self, word):
ref = self.data['ref']
for char in word:
if char not in ref:
ref[char] = {}
ref = ref[char]
ref['\3'] = True
if len(word) > self.max_word_size:
self.max_word_size = len(word)
self.word_num += 1
def find(self,content):
ret = []
ref = self.data['ref']
content_size = len(content)
for idx,char in enumerate(content):
if not ref.has_key(char):continue
tmp_word_size,tmp_ref = 1,ref[char]
while tmp_word_size <= self.max_word_size:
if tmp_ref.get("\3",False):
return True,content[idx:idx+tmp_word_size]
if idx + tmp_word_size >= content_size:
break
tmp_char = content[idx+tmp_word_size]
if tmp_char not in tmp_ref:
break
tmp_word_size += 1
tmp_ref = tmp_ref[tmp_char]
return False,None
def load(self,rfile):
if not os.path.exists(rfile):
return False
try:
self.data = json.loads(open(rfile).read())
except Exception as e:
if self.logger:
self.logger.warn("trie load error\t%s" % str(e))
self.data = {'ref':{}}
return False
return True
def dump(self,rfile):
json.dump(self.data,open(rfile,"w"),ensure_ascii=False)
if __name__ == "__main__":
inst = Trie()
inst.add(u'主播')
print json.dumps(inst.data,ensure_ascii=False)
code,word = inst.find(u'标题: 韩国女主播青草女主播学生装热舞(9)')
print code,word
find方法可以快速放回第一个命中的关键词,时间复杂度为length(content)。
ref:https://zh.wikipedia.org/wiki/Trie