小白实现搜索引擎匹配模式
需求
部门需要实现一个匹配规则,例如 输入 格力空调维修 可以检索到格力空调维修电话、格力空调上面维修服务等等 和输入的关键词相关的数据库中的文章 类似于一个搜索引擎的检索模式
试过的方法
1、jieba+re
当时提出找个需求的时候 我的大概思路是 先对输入的关键词进行分词处理 然后对拿到的词写正则规则 进行查询 但是后来发现效果不太理想,总会匹配出其他不相关的标题 当然也有很大一部分原因是因为我的正则写得不够完善,但是 如果是将所有情况都写入的话 那是一个比较浩大的工程了 找个方案直接被我抛弃
2、synonyms判断句子相关度
import synonyms
def judge_similarity(k1, k2):
r = synonyms.compare(k1, k2, seg=True)
return r
传入K1,K2这两个句子 会返回他们俩的相关度 这个方法可以粗略的实现需求,根据需求对返回的相关系数进行判断可以自己设置一个阈值,但是依旧会发生匹配得不够准确的情况,例如 空调维修 和车载空调维修,这并不是希望看到的结果,这种方案可以当做一个备选方案
最终实现
思路
某一天早上 需求方来问这个功能的进度,我当时心中苦不堪言,PHP都有专门的框架可以实现这个功能,但是python没有(可能有 但是我没找到0.0),人家度娘这么大个团队弄的东西让我一个才毕业没多久的小白来弄,有过两个方案效果还不太好,在和需求方解(狡)释(辩)的过程当中我突然灵机一动,想到了第三种方案。
jieba的分词结果对相同的词是一样的,就比如 格力空调 使用搜索引擎的分割方式会得到
[格力,空调,格力空调]
这三个词语,只要这四个字出现在关键词或者标题当中 而不用担心 这四个字出现在什么地方
,比如格力空调维修 和 维修格力空调 分词的结果必定相同,直接对关键词和标题的分词结果进行比对 可以排除一些因为语序上的不同,而导致的完全匹配不能匹配出来的情况,为了方便对结果集进行比较 我将分词之后的结果转换为了集合而不是list
在实现了上诉功能后,会得到两个结果集,这两个结果集合 分别为A,B 我大致分为了一下几种情况:
1、子集于父集合关系 (一个是另一个的子集)
2、不是子集与父集关系,但是有交集
3、不是子集与父集关系,也没用交集
分别探讨一下这几种情况:
情况1:
关键词和标题是包含关系,关键词包含标题或者标题包含关键词 这种情况是我希望看到的
例如: 格力空调 和 格力空调维修
情况2:
关键词和标题有交集 证明有重复的字出现,但是又有分别的特征,两个句子是否讲诉的同一件事不得而知 例如 格力空调漏水 和 格力空调外机坏了
情况3:
完全不相关 例如: 格力空调 TCL电视这种情况
问题1:有近义描述
在我的文章库当中 有很多 XXX怎么解决、XXX如何解决 ,XXX怎么办这样的东西 我们关心的只是XXX的内容 后面的副词和语气助词我们并不关心,所以我根据自己的文章库 将常见的一些没用的词进行了剔除,删除掉 怎么,如何,为什么,怎么办…这些词语把他们定为了一个屁话集(没错 在我看来这些词就是屁话)
问题2:小瑕疵
在上面的讨论当中 第一种情况 假设A是keyword的结果集 B是title的结果集有两种情况
1、A包含B 2、B包含A 如果A包含B是我能接受的 这种情况表示查询的关键词比这个文章的标题更加的详细 就比如 格力空调外机清洗 和 格力空调清洗 这是我可以接受的结果
第二种情况 :B包含A 这种情况表示文章的标题比我给定的更加详细 有一定的误差 因此我构建了一个not_like 记录这种情况 差集当中如果出现not_like里的词语 就默认他们不相关
demo
import jieba
from parsedata.tools import SQLDB
class mySql(SQLDB):
def read(self):
sql = 'SELECT * FROM keywords'
cur = self.db.cursor()
cur.execute(sql)
# infos = cur.fetchall()
for i in cur.fetchall():
title, *_ = i
yield title
def parseword(word):
pihua = ['被', '了', '怎么', '怎么办', '?', '什么', '如何', '的', '原因', '为何', '回事', '解决', '是', '和', '问题', '维修', '修', '修理', '正确',
'哪些', '咋', '怎么回事', '?', '为什么', '}', '{', '多少', '不', '怎样', '好', '办法', '专业', '附近', '方法']
remove_list = []
word = word.strip().replace(' ', '')
cword = jieba.lcut_for_search(word)
for word in cword:
if word in pihua:
remove_list.append(word)
if remove_list:
for word in remove_list:
cword.remove(word)
return set(cword)
def run(keyword):
cword = parseword(keyword)
for title in db.read():
a = parseword(title)
if cword >= a:
# print('原标题: {}----->{} {} >= {}'.format(keyword, title, cword, a))
return title
elif cword <= a:
not_like = ['制冷', '打孔', '清洗', '修理', '堵塞', '安装', '疏通', '加氟', '拆卸', '拆盖', '改', '拆洗']
Difference_set = list(a - cword)
flag = False
# print('!!! 丝毫不相干:{} | {}'.format(keyword, title))
for i in Difference_set:
if i in not_like:
flag = True
break
if flag:
pass
else:
# print('差集:{} title1:{} title2:{}'.format(a - cword, keyword, title))
return title
# else:
# print('丝毫不相干:{} | {}'.format(keyword, title))
if __name__ == '__main__':
db = mySql()
keyword = 'TCL冰箱如何正确清洗'
word = run(keyword)
print(word)