python搜索引擎之搜索系统的建立——根据关键字命中次数排分给出前若干个答案
2015-11-13 00:09
696 查看
根据前面的博客建立了如下的各种索引库的表:
后向索引有两个表项,其中第一个表项是后向索引表,其指定每个wordId,以及出现过该关键字的doc 的数量,同时还有该关键字的 doc hits 在后面一个表中的偏移,后一个表是后向表,记录了docId,以及对应当前关键字的hitlist,关于后向索引表的具体内容,百度吧。。实现是为了根据偏移快速定位到对应的docId的位置,人为增加了一列 docIdIndex项,两个表如下:
上述两个表的关系是:第一个表中的 wordId 出现过的网页的编号(docId)的连续存在第二个表中,第一个表中 offset 指出了存储编号的起始位置,该位置接下来的 nDocs个表项都是对应 wordId 出现过的 wordId
BackwardObj 列表。具体见下 return current_set
(2)findKeyWordDocId
self.cursor.execute("SELECT * FROM backwardIndexTable WHERE wordId = (?)",(word_id,)) #过滤表项
info = self.cursor.fetchone() #抓出该表项 ndocs_offset.append(info[1]) # 将表项中的第一项,即 ndocs 放入返回列表的第一项 ndocs_offset.append(info[2])
# 将 offset 放入返回列表的第二项 return ndocs_offset
(3)getSetFromBT
self.cursor.execute("SELECT * FROM backwardTable WHERE docIdIndex between (?) and (?)",(doc_id_index_beg,doc_id_index_end)) total_info = self.cursor.fetchall(); for info in total_info: current_set.append(BackwardObj(info[1],info[2],info[3])) # 解析每一个表项并建立对应的每个
BackwardObj 对象,将其加入 list中 return current_set
1.词典(对每个关键字分配一个 wordId)
词典放在命名为 backwardTableDb.db 中的 wordIdTable 中,见部分字典截图如下:
2.建立后向索引,及相关表项
后向索引有两个表项,其中第一个表项是后向索引表,其指定每个wordId,以及出现过该关键字的doc 的数量,同时还有该关键字的 doc hits 在后面一个表中的偏移,后一个表是后向表,记录了docId,以及对应当前关键字的hitlist,关于后向索引表的具体内容,百度吧。。实现是为了根据偏移快速定位到对应的docId的位置,人为增加了一列 docIdIndex项,两个表如下:上述两个表的关系是:第一个表中的 wordId 出现过的网页的编号(docId)的连续存在第二个表中,第一个表中 offset 指出了存储编号的起始位置,该位置接下来的 nDocs个表项都是对应 wordId 出现过的 wordId
3.基本思想描述:
对输入的搜索语句,先进行分词,对每个关键字,根据后向索引表,找到对应的命中 docId 的 set,综合所有set评估docId,最后哪个docId 中命中的关键字个数越多,该docId 对应的网页越符合搜索需求。4.代码段解释
4.1 建一个类来存储后向索引找到的对象,记录 doc_id,nhits,以及 hitList(字符串,分别记录命中的起始与结束位置)
class BackwardObj: doc_id = 0 nhits = 0 hit_list = '' def __init__(self,t_doc_id,t_nhits,t_hit_list): self.doc_id = t_doc_id self.nhits = t_nhits self.hit_list = t_hit_list[:] # Python 中 list 与 dictionary 均是引用,避免此处引用
4.2 定义一个中枢类,用来控制数据库的链接,存储词典
class CentralControl: conn = sqlite3.connect("backwardTableDb.db") #conn 控制后向数据库 cursor = conn.cursor() org_conn = sqlite3.connect("orgDb.db") #org_conn 控制原始数据库,用于在找到结果 docId 后,找出标题内容 org_cursor = org_conn.cursor() word_id_dic = {}<span style="white-space:pre"> </span>#词表,内容是 {关键字:关键字Id} def __init__(self): self.loadWordIdDic() #构造函数内读入词典 def loadWordIdDic(self): self.cursor.execute("SELECT * FROM wordIdTable") # SQL 语法抓出词典表内所有内容 word_id_data = self.cursor.fetchall() for word_id_obj in word_id_data: self.word_id_dic[word_id_obj[0]] = word_id_obj[1] # 将抓出的每个内容放入词典中
4.3 定义查找函数,以下所有函数均是中枢类的成员函数,(为了能快速访问词典并使用数据库连接)
def oneSearch(self,query): # query 存储搜索字符串 query = query.lower() # 若存在大写字符,转到小写 seg_list = jieba.cut_for_search(query) #使用 jieba 分词,将搜索字符串进行分词 seg_list = list(seg_list) # 将分词结果放在 List 中 if ' ' in seg_list: #deal ' ' seg_list = [i for i in seg_list if i != ' '] # 将关键字中的空格字符去掉,注意 seg_list.remove(" ")仅能删除第一个空格 <span style="white-space:pre"> </span># 建立一个字典。{关键字:[每个命中的表项形成一个BackwardObj 对象(上面定义),多个对象列表]} set_dic = {} for key_word in seg_list: current_set = self.getDocSet(key_word) #调用函数找到该关键字对应的 BackwardObj 对象列表(根据后向表查找),具体定义见下 if len(current_set) != 0 :<span style="white-space:pre"> </span> # 若找到了该关键字对应的对象列表 set_dic[key_word] = current_set # 将该关键字与列表加入上面定义的关键字为键值的字典中 <pre name="code" class="python"><span style="white-space:pre"> </span># 根据所有关键字及其对应的命中 docId set 的综合,建立一个 list,里面存储的是一个个元组,其中第一个元素是 docId,第二个元素是该 docId 命中的关键字的个数,且该 list 是按命中关键字个数从高到低排序的。具体代码见下。doc_set = self.getDocIdScores(set_dic) if len(doc_set) != 0: self.printDocInfo(doc_set) # 否则,打印找到的信息,具体代码见下 else: #若一个对应页面均没有找到,则说明没有找到相关信息 print "not find information"
4.4 根据关键字,获取该关键字在后向表中对应表项组成的对象列表(getDocSet)
(1)getDocSetdef getDocSet(self,key_word): current_set = []<pre name="code" class="python"><span style="white-space:pre"> </span>
<span style="white-space:pre"> </span># 调用函数找到该关键字在后向索引表中的表项值,即命中 doc 数与命中信息表项的偏移。具体见下[ndocs,offset] = self.findKeyWordDocId(key_word) if ndocs == 0 and offset == 0 : # 若当前关键字不在字典中 return current_set # 返回空列表 current_set = self.getSetFromBT(ndocs,offset) # 根据后向索引表中的信息,去后向表中寻找对应表项,并建立
BackwardObj 列表。具体见下 return current_set
(2)findKeyWordDocId
def findKeyWordDocId(self,key_word): ndocs_offset = [] if not self.word_id_dic.has_key(key_word): # 若当前关键字不在字典中,则返回 ndocs = 0,offset = 0,协助 getDocSet 判断 ndocs_offset.append(0) ndocs_offset.append(0) return ndocs_offset word_id = self.word_id_dic[key_word] # 根据字典获取当前关键字的 wordId <pre name="code" class="python" style="font-size:14px;"><span style="white-space:pre"> </span># 使用SQL 语法抓出当前 wordId 在后向索引表中的对应表项
self.cursor.execute("SELECT * FROM backwardIndexTable WHERE wordId = (?)",(word_id,)) #过滤表项
info = self.cursor.fetchone() #抓出该表项 ndocs_offset.append(info[1]) # 将表项中的第一项,即 ndocs 放入返回列表的第一项 ndocs_offset.append(info[2])
# 将 offset 放入返回列表的第二项 return ndocs_offset
(3)getSetFromBT
def getSetFromBT(self,ndocs,offset): current_set = [] doc_id_index_beg = offset + 1 # 算出偏移量对应的 docIdIndex 的起始值,即为什么要加一项 docIdIndex doc_id_index_end = doc_id_index_beg + ndocs - 1 # 算出偏移量对应的 docIdIndex 的结束位置 <pre name="code" class="python"><span style="white-space:pre"> </span># 根据SQL 语法,抓出对应所属位置的表项
self.cursor.execute("SELECT * FROM backwardTable WHERE docIdIndex between (?) and (?)",(doc_id_index_beg,doc_id_index_end)) total_info = self.cursor.fetchall(); for info in total_info: current_set.append(BackwardObj(info[1],info[2],info[3])) # 解析每一个表项并建立对应的每个
BackwardObj 对象,将其加入 list中 return current_set
4.5 对每个关键字命中的 docId 进行统计,统计每个出现过关键字的 docId 命中关键字的个数,并按照命中个数由多到少进行排序
def getDocIdScores(self,set_dic): doc_score_dic = {} # 建立字典,键是 docId,而值是该 docId 命中关键字的个数,以下简称doc命中字典 for key in set_dic: # 遍历关键字及命中 doc 序列组成的字典 for obj in set_dic[key]: # 对每个关键字,遍历命中该关键字的表项构成的对象 BackwardObj if doc_score_dic.has_key(obj.doc_id): # 为该 docId 的命中次数累加 doc_score_dic[obj.doc_id] += 1 else: doc_score_dic[obj.doc_id] = 1 doc_score_set = sorted(doc_score_dic.iteritems(),key = lambda d : d[1],reverse = True) # 根据doc 命中字典中的命中次数进行排序 return doc_score_set
4.6 根据 doc 命中字典显示查询结果:
def printDocInfo(self,doc_set): index = 0 while index < 8: //默认返回命中关键字个数最多的前八个 title doc_id = doc_set[index][0] hit_times = doc_set[index][1] index += 1 self.org_cursor.execute("SELECT title, url FROM orgTable WHERE id == (?)",(doc_id,)) info = self.org_cursor.fetchone() print "title : ",info[0] print "url : ",info[1] print "hits : ",hit_times print "------------------------------------"
4.7 上面所有函数均定义为中枢类的成员函数,main函数中的调用代码如下:
if __name__ == "__main__": central_control = CentralControl() while True: query = raw_input("input query:") central_control.oneSearch(query) central_control.conn.close() central_control.org_conn.close()
相关文章推荐
- python开发之文件操作用法实例
- python编程开发之类型转换convert实例分析
- python编程开发之日期操作实例分析
- Python编程入门之Hello World的三种实现方式
- Python的Flask框架的简介和安装方法
- Python下的常用下载安装工具pip的安装方法
- 深入解析Python中的urllib2模块
- Python设置Socket代理及实现远程摄像头控制的例子
- 使用Python下载歌词并嵌入歌曲文件中的实现代码
- Python的pycurl包用法简介
- 简单了解Python下用于监视文件系统的pyinotify包
- Python下rrdtool模块的基本使用方法
- 浅析Python中signal包的使用
- python的requests初步使用
- python无脑搜索引擎实现<一>
- python小练习之换零钱
- Python开发包推荐系列之xml、html解析器PyQuery
- Python笔记004——字符串
- Ubuntu14.04下安装Python2.7+Theano0.7+CUDA7.5
- Odoo8 custom view module