用Python做一个简单的搜索引擎

作者 张旭 日期 2017-12-09
用Python做一个简单的搜索引擎

用Python做一个简单的搜索引擎

我们在用百度、谷歌等搜东西的时候,也许会想,搜索引擎是怎么找出这些相关的东西的呢?
本文,我将用Python和相关工具做一个搜索引擎,实现搜索引擎的核心原理。
(至于效果,额… 当然和百度谷歌有不少的差距,我不说了嘛,只是实现核心原理,并力求不写太多的代码)

原理

让我们来思考这样一个问题:,当你在搜索引擎上搜索一个词的时候,你想把与输入内容最匹配的网页显示在前面。
那么我们搜索的任务就变成了根据输入内容,对网页与输入内容的重要性打分排序的任务。

假如,我们要搜索 “美国对朝鲜的核武器政策”
首先我们对这句话分词,并去除常用词,得到 ‘美国 朝鲜 核武器 政策’
直观来考虑,我们要统计每个词语在每篇文章中出现的频率,然后将频率之和相加,排序,频率和高文章就排在前面
每个词在每篇文章中的频率叫做TF (term frequency)

但是这样作就没问题吗?
比如,’美国’ 这个在网络中的频率要必’朝鲜’,’核武器’更高,’政策’也是。
如果我们将频率和相加对文档排序,那么含有”美国”,和”政策”的文档,将会排在前面,虽然这些文档并不是有关朝鲜和美国核政策的。

这时我们就需要对每个词语的重要性作量化,也就是说,在全部文档中,”美国”,”政策” 要比 ”核武器“ ”政策“ 出现的多,按照信息论的解释来说,就是后者提供的信息更多

假设词语w 在 D 个文档中共有Dw个文档包含w词,常用的一项指标是IDF = log(D/Dw) (Dw和D 通常会加1处理,拉普拉斯平滑)来表达词语出现的频率次数。IDF(Inverse documentfrequency)叫做“逆文本频率指数。

一个查询词的贡献度现在变成了 TF×IDF。
那么我们就要计算 查询词的TF×IDF之和就好了。

import nltk
import re
import jieba
import os
from functools import reduce

工具

使用结巴分词;一个搜狗语料库;

读入数据

我们以搜狗的一个新闻数据集为例,来用简短的Python代码实现一个简单的TF-IDF”搜索引擎”

all_Texts = []
count= 0
err_count = 0
folder = 'corpus'
for f_name in os.listdir(folder):
try:
with open(folder+'/'+f_name,encoding='GBK',errors='ignore') as f:
all_Texts.append(f.read())
count+=1
#print(count,end=';')
except Exception as e:
print('ERROR',f_name,err_count,end=';')
err_count+=1

预处理

加载停用词表,停用词是一些很常见,但对句子的构成意义不大的常见字的集合,比如’的,是,is and ‘

with open('stopwords.txt') as f_stop:
stop_words = [i.strip('\n') for i in f_stop.readlines()]
my_own_stop_words = ['nbsp']
stop_words += my_own_stop_words

我们使用分词工具是jieba .这个函数去除停用词,并分词

def text_process(text):
pattern = '[\u4e00-\u9fa5|[0-9a-zA-Z]{1,}'
#print('===============RAW=====================',text,sep='\n')
chinesewords = re.findall(pattern,text)
#print('================find Chinese======================',chinesewords,sep='\n')
raw_words = [word for word in re.findall(pattern,text) if word not in stop_words]
#print('===============remove stopwords=====================',raw_words,sep='\n')
cuted_words = [list(jieba.cut(i)) for i in raw_words]
#print('===============Jieba cuted_words=====================',cuted_words,sep='\n')
used_words=list(filter(lambda x:x not in stop_words,reduce(lambda x,y:x+y,cuted_words)))
#print('===============remove jeba stopwords=====================',a,sep='\n')
return used_words

使用sklean 中相关工具,统计词频

from sklearn.feature_extraction.text import CountVectorizer

对文档库中出现的词语编号

# Might take awhile...
bow_transformer = CountVectorizer(analyzer=text_process).fit(all_Texts)
Building prefix dict from the default dictionary ...
Loading model from cache /tmp/jieba.cache
Loading model cost 0.642 seconds.
Prefix dict has been built succesfully.

统计词库中bow_transformer 在每个文档中出现的次数,得到词语-文档,次数矩阵

messages_bow = bow_transformer.transform(all_Texts)

得到每个词在每个文档中的TF-IDF矩阵

from sklearn.feature_extraction.text import TfidfTransformer
tfidf_transformer = TfidfTransformer().fit(messages_bow)
messages_tfidf = tfidf_transformer.transform(messages_bow)

搜索

s_words = input('请输入搜索内容:')
请输入搜索内容:企鹅 南极

使用和生成IDF一样的词处理办法来查询词

key_words=text_process(s_words)
print(key_words)
['企鹅', '南极']

获取查询词的index

key_words =[bow_transformer.vocabulary_.get(i) for i in key_words if bow_transformer.vocabulary_.get(i)]

获取包含查询词的文档集合的index

message_idx = [messages_tfidf[:,i].nonzero()[0] for i in key_words]
message_idx = list(reduce(lambda x,y:set(x)|set(y),message_idx))

计算上述文档中,查询词的TF-IDF之和

TFIDFS = [sum([messages_tfidf[i,j] for j in key_words]) for i in list(message_idx)]

文档index ,TF-IDF和字典对应

idx_tfidf = dict(zip(message_idx,TFIDFS))

按照tfidf排序

sorted_idxs = sorted(message_idx,key=lambda x:idx_tfidf[x],reverse=True)

根据文档index,检索文本库

for i,mess in enumerate(sorted_idxs[:10]):
print('==============',i,idx_tfidf[mess],'===================')
print(all_Texts[mess][:100],'........')
============== 0 0.845949552012 ===================

   遥远而神秘的冰雪大陆--南极,以其无与伦比的自然风光和奇妙独特的刺激感受,强烈地吸引着世界旅游者的目光。作为中国一个普通公民,何时可以到南极去旅游?带着这个令每一位读者都怦然心动的问题,记者采 ........
============== 1 0.667916619709 ===================

  英国科学家发现,被厚厚冰层所覆盖的南极湖泊湖水相连,形成一个庞大的地下水系。由于南极湖泊相互之间并非是人们所设想的隔离状态,对任何湖泊的钻探都可能导致整个水系的污染,因此科学家呼吁要慎重勘探南极 ........
============== 2 0.667916619709 ===================

  英国科学家发现,被厚厚冰层所覆盖的南极湖泊湖水相连,形成一个庞大的地下水系。由于南极湖泊相互之间并非是人们所设想的隔离状态,对任何湖泊的钻探都可能导致整个水系的污染,因此科学家呼吁要慎重勘探南极 ........
============== 3 0.531403456215 ===================

  大自然的力量,究竟有多大?人类的体能和意志,有没有极限?日前,人类首次划皮艇征服南极的戈尔“冒险哲学”探险队抵达中国展开中国巡回秀,他们通过精美的图片展和大量的影像资料,在广州[图库]向户外运动 ........
============== 4 0.500867204563 ===================
  中国日报网站消息:中国拟在南极中山站建设一部高频雷达,用于对极区空间环境的探测和研究。而这个纯粹的科考项目却引起了美国军方的“关注和担忧”。美国《世界论坛报》2月2日报道说,美国军事专家担心中国此 ........
============== 5 0.480971843171 ===================





好望角上的震撼 
  孩提时神往的好望角,就在眼前。 
  好望角在开普敦半岛最南端,这里是保留了500年前原生态的自然保护区。在大西洋边红色的卵石滩上,时常可见驼鸟闲庭信步的可爱模样。 
 ........
============== 6 0.434699161277 ===================
  撰稿/葛叶龙  如果南极洲塌陷了,毫无疑问将对全球产生巨大影响——当然,这不是明天就会发生的事,南极洲可是个大家伙。  从飞机上看下去,南极艾博特(Abbott)冰架是白茫茫一片,再往前看,是一直 ........
============== 7 0.358458239071 ===================
  一直以为企鹅、海豹这类生物只有在南极这样的地方才会看见,亲临南非,才发现南非原来也有这种生存在冰冷地带的动物。如果你圣诞行程匆忙而来不及欣赏这些可爱的动物也不要失望,你可以选择夏天的时候去南非,炎 ........
============== 8 0.339872478483 ===================

  临床医生和牙医都利用121 ℃的高压蒸汽来灭菌消毒,因为在这么高的温度中所有的生物都会死掉。可是一些新发现的细菌却是例外,它们不仅在121 
℃中还生长良好,在130 ℃的高温中还能够生存。 
 ........
============== 9 0.336407059772 ===================

  新华网伦敦4月20日电 英国科学家日前宣布,他们在南极冰层下发现了河流。这些河流可能连接着冰下湖。
  伦敦大学学院和自然环境研究协会极地观测中心的科学家研究了欧洲航天局ERS-2卫星对南极东部 ........

大功告成!!! 这样你就可以自建语料库,生成TF-IDF矩阵,完成查询啦!,如果文中还有链接,那么就可以再此基础上对网页用Pagerank算法排序,这就是一个现代意义上搜索引擎的雏形了。