用python做一个搜索引擎(Pylucene)的实例代码


Posted in Python onJuly 05, 2017

1.什么是搜索引擎?

搜索引擎是“对网络信息资源进行搜集整理并提供信息查询服务的系统,包括信息搜集、信息整理和用户查询三部分”。如图1是搜索引擎的一般结构,信息搜集模块从网络采集信息到网络信息库之中(一般使用爬虫);然后信息整理模块对采集的信息进行分词、去停用词、赋权重等操作后建立索引表(一般是倒排索引)构成索引库;最后用户查询模块就可以识别用户的检索需求并提供检索服务啦。

用python做一个搜索引擎(Pylucene)的实例代码

图1 搜索引擎的一般结构

2. 使用python实现一个简单搜索引擎

2.1 问题分析

从图1看,一个完整的搜索引擎架构从互联网搜集信息开始,可以使用python编写一个爬虫,这是python的强项。

接着,信息处理模块。分词?停用词?倒排表?what?什么乱七八糟的?不用管它,我们有前辈们造好的轮子---Pylucene(lucene的python封装版本,Lucene能够帮助开发者为软件、系统增添检索功能。Lucene是一套用于全文检索和搜寻的开源程序库)。使用Pylucene可以简单的帮助我们完成对采集到的信息进行处理,包括索引的建立和搜索。

最后,为了能在网页上使用我们的搜索引擎,我们使用flask这个轻量级 Web 应用框架做一个小网页获取搜索语句并反馈搜索结果。

2.2 爬虫设计

主要搜集以下内容:目标网页的标题、目标网页的主要文字内容、目标网页指向其他页面的URL地址。网络爬虫的工作流程如图2所。爬虫的主要数据结构是队列。首先,起始的种子节点进入队列,然后从队列中取出一个节点访问,抓取该节点页面上的目标信息,再将该节点页面指向其他页面的URL链接放进队列,再从队列中取出新的节点进行访问,直至队列为空。通过队列“先进先出”的特点实现广度优先的遍历算法,逐个访问站点的每一页面。

用python做一个搜索引擎(Pylucene)的实例代码

图2

2.3 pylucene的使用

Pylucene中关于建立索引的类主要有Directory、Analyzer、IndexWriter、Document、Filed。

Directory是Pylucene中关于文件操作的类。它有SimpleFSDirectory和RAMDirectory、CompoundFileDirectory、FileSwitchDirectory等11个子类,列举的四个是与索引目录的保存相关的子类,SimpleFSDirectory是将构建的索引保存至文件系统之中;RAMDirectory是将索引保存至RAM内存之中;CompoundFileDirectory是一种复合的索引保存方式;而FileSwitchDirectory允许临时切换索引的保存方式以发挥各种索引保存方式的优点。

Analyzer,分析器。它是对爬虫获得的将要进行构建索引的文本进行处理的类。包括了文本进行分词操作、去掉停用词、转换大小写等操作。Pylucene自带了若干分析器,构建索引时也可使用第三方分析器或者自写分析器。分析器的好坏关系到构建索引的质量与搜索服务的所能提供的精准度与速度。

IndexWriter,索引写入类。在Directory开辟的储存空间中IndexWriter可以进行索引的写入、修改、增添、删除等操作,但不可进行索引的读取也不能搜索索引。

Document,文档类。在Pylucene中建立索引的基本单位是“文档”(Document),一个Document可能是一个网页、一篇文章、一封邮件。Document是用以构建索引的单位同时也是进行搜索时的结果单位,对它进行合理的设计能够提供个性化的搜索服务。

Filed,域类。一个Document之中可以包含多个域(Field)。Filed是Document的组成部分,就如一篇文章的组成可能是文章标题、文章主体、作者、发表日期等多个Filed。

将一个页面作为一个Document,包含三个Field分别是页面的URL地址(url)、页面的标题(title)、页面的主要文字内容(content)。对于索引的储存方式选择使用SimpleFSDirectory类,将索引保存至文件之中。分析器选择Pylucene自带的CJKAnalyzer,该分析器对中文支持较好,适用于中文内容的文本处理。

使用Pylucene构建索引的具体操作步骤如下:

lucene.initVM()

INDEXIDR = self.__index_dir

indexdir = SimpleFSDirectory(File(INDEXIDR))①

analyzer = CJKAnalyzer(Version.LUCENE_30)②

index_writer = IndexWriter(indexdir, analyzer, True, IndexWriter.MaxFieldLength(512))③

document = Document()④

document.add(Field("content", str(page_info["content"]), Field.Store.NOT, Field.Index.ANALYZED))⑤

document.add(Field("url", visiting, Field.Store.YES, Field.Index.NOT_ANALYZED))⑥

document.add(Field("title", str(page_info["title"]), Field.Store.YES, Field.Index.ANALYZED))⑦

index_writer.addDocument(document)⑧

index_writer.optimize()⑨

index_writer.close()⑩

索引的构建有10个主要的步骤:

①实例化一个SimpleFSDirectory对象,将索引保存至本地文件之中,保存的路径为自定义的路径“INDEXIDR”。

②实例化一个CJKAnalyzer分析器,实例化时的参数Version.LUCENE_30为Pylucene的版本号。

③实例化一个IndexWriter对象,所携带的四个参数分是前面的实例化的SimpleFSDirectory对象和CJKAnalyzer分析器,布尔型的变量true表示创建一个新的索引,IndexWriter.MaxFieldLength指定了一个索引最大的域(Filed)数量。

④实例化一个Document对象,取名为document。

⑤为document添加名称为“content”的域。该域的内容为爬虫获取的某一网页页面的主要文字内容。该操作的参数是实例化并马上使用的Field对象;Field对象的四个参数分别是:

(1)“content”,域的名称。

(2)page_info["content"],爬虫搜集到的网页页面的主要文字内容。

(3)Field.Store是用于表示该域的值是否可以恢复原始字符的变量,Field.Store.YES表示存储在该域中的内容可以恢复至原始文本内容,Field. Store.NOT表示不可恢复。

(4)Field.Index变量表示该域的内容是否应用分析器处理,Field. Index.ANALYZED表示对该域字符处理使用分析器,Field. Index. NOT_ANALYZED则表示不对该域使用分析器处理字符。

⑥添加名称为“url”的域用以保存该页面地址。

⑦添加名称为“title”的域用以保存该页面的标题。

⑧实例化IndexWriter对像将文档document写入索引文件。

⑨优化索引库文件,合并索引库中的小文件为大文件。

⑩单个周期内构建索引操作完成后关闭IndexWriter对像。

Pylucene关于建立索引的搜索的类主要有IndexSearcher、Query、QueryParser[16]。

IndexSearcher,索引搜索类。用于在IndexWriter构建的索引库中进行搜索操作。

Query,描述查询请求的类。它将查询请求递交给IndexSearcher完成搜索操作。Query拥有许多子类以完成不同的查询请求。例如TermQuery是按词条搜索,它是最基本最简单的查询类型,用来在指定域中匹配特定项的文档;RangeQuery,指定范围内搜索,用于在指定域中匹配特定范围内的文档;FuzzyQuery,一种模糊查询,能够简单地识别近义词匹配与查询关键字语义相近的项。

QueryParser,Query解析器。需要实现不同的查询需求时必须使用Query提供的不同子类,导致Query使用起来容易造成混乱。因而Pylucene还提供了Query语法解析器QueryParser。QueryParser能够解析提交的Query语句,根据Query语法挑选合适Query子类完成相应的查询,开发者不必关心底层使用的是什么Query实现类。例如Query语句“关键字1 and 关键字2” QueryParser解析为查询同时匹配关键字1和关键字2的文档;Query语句“id[123 to 456]” QueryParser解析成为查询名称为“id”的域中的值在指定范围“123”到“456”之间的文档;Query语句“关键字 site:www.web.com”QueryParser解析成为查询同时满足名称为“site”的域中值为“www.web.com” 和匹配“关键字”两个查询条件的文档。

索引的搜索是Pylucene所专注的领域之一,为实现索引的搜索编写了一个名为query的类,query实现索引的搜索有以下主要步骤:

lucene.initVM()

if query_str.find(":") ==-1 and query_str.find(":") ==-1:

query_str="title:"+query_str+" OR content:"+query_str①

indir= SimpleFSDirectory(File(self.__indexDir))②

lucene_analyzer= CJKAnalyzer(Version.LUCENE_CURRENT)③

lucene_searcher= IndexSearcher(indir)④

my_query = QueryParser(Version.LUCENE_CURRENT,"title",lucene_analyzer).parse(query_str)⑤

total_hits = lucene_searcher.search(my_query, MAX)⑥

for hit in total_hits.scoreDocs:⑦

      print"Hit Score: ", hit.score

      doc = lucene_searcher.doc(hit.doc)

      result_urls.append(doc.get("url").encode("utf-8"))

      result_titles.append(doc.get("title").encode("utf-8"))

      print doc.get("title").encode("utf-8")

 

 result = {"Hits": total_hits.totalHits, "url":tuple(result_urls), "title":tuple(result_titles)}

 return result

索引的搜索有7个主要的步骤:

①首先对搜索语句进行判断,若语句不是针对标题或文章内容进行单一域的查询,即不包含关键词“title:”或“content:”时默认搜索title和content两个域。

②实例化一个SimpleFSDirectory对象,指定它的工作路径为先前创建索引的路径。

③实例化一个CJKAnalyzer分析器,搜索时使用的分析器应与索引构建时使用的分析器在类型版本上均一致。

④实例化一个IndexSearcher对象lucene_searcher,它的参数为第○2步的SimpleFSDirectory对象。

⑤实例化一个QueryParser对象my_query,它描述查询请求,解析Query查询语句。参数Version.LUCENE_CURRENT为pylucene的版本号,“title”指默认的搜索域,lucene_analyzer指定了使用的分析器,query_str是Query查询语句。在实例化QueryParser前会对用户搜索请求作简单处理,若用户指定了搜索某个域就搜索该域,若用户未指定则同时搜索“title”和“content”两个域。

⑥lucene_searcher进行搜索操作,返回结果集total_hits。total_hits中包含结果总数totalHits,搜索结果的文档集scoreDocs,scoreDocs中包括搜索出的文档以及每篇文档与搜索语句相关度的得分。

⑦lucene_searcher搜索出的结果集不能直接被Python处理,因而在搜索操作返回结果之前应将结果由Pylucene转为普通的Python数据结构。使用For循环依次处理每个结果,将结果文档按相关度得分高低依次将它们的地址域“url”的值放入Python列表result_urls,将标题域“title”的值放入列表result_titles。最后将包含地址、标题的列表和结果总数组合成一个Python“字典”,将最后处理的结果作为整个搜索操作的返回值。

用户在浏览器搜索框输入搜索词并点击搜索,浏览器发起一个GET请求,Flask的路由route设置了由result函数响应该请求。result函数先实例化一个搜索类query的对象infoso,将搜索词传递给该对象,infoso完成搜索将结果返回给函数result。函数result将搜索出来的页面和结果总数等传递给模板result.html,模板result.html用于呈现结果

如下是Python使用flask模块处理搜索请求的代码:

app = Flask(__name__)#创建Flask实例

@app.route('/')#设置搜索默认主页

def index():

html="<h1>title这是标题</h1>"

return render_template('index.html')

@app.route("/result",methods=['GET', 'POST'])#注册路由,并指定HTTP方法为GET、POST

def result(): #resul函数

if request.method=="GET":#响应GET请求

key_word=request.args.get('word')#获取搜索语句

  if len(key_word)!=0:

   infoso = query("./glxy") #创建查询类query的实例

    re = infoso.search(key_word)#进行搜索,返回结果集

    so_result=[]

    n=0

    for item in re["url"]:

temp_result={"url":item,"title":re["title"][n]}#将结果集传递给模板

    so_result.append(temp_result)

        n=n+1

    return render_template('result.html', key_word=key_word, result_sum=re["Hits"],result=so_result)

  else:

    key_word=""

  return render_template('result.html')

if __name__ == '__main__':

  app.debug = True

  app.run()#运行web服务

以上这篇用python做一个搜索引擎(Pylucene)的实例代码就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
简单谈谈Python流程控制语句
Dec 04 Python
python编程嵌套函数实例代码
Feb 11 Python
python基础教程项目四之新闻聚合
Apr 02 Python
Python 循环语句之 while,for语句详解
Apr 23 Python
Python使用itertools模块实现排列组合功能示例
Jul 02 Python
Python骚操作之动态定义函数
Mar 26 Python
python 实现GUI(图形用户界面)编程详解
Jul 17 Python
Python 脚本拉取 Docker 镜像问题
Nov 10 Python
tensorflow estimator 使用hook实现finetune方式
Jan 21 Python
django数据模型中null和blank的区别说明
Sep 02 Python
Pytorch之Tensor和Numpy之间的转换的实现方法
Sep 03 Python
pandas中pd.groupby()的用法详解
Jun 16 Python
Python对象类型及其运算方法(详解)
Jul 05 #Python
python数据预处理之将类别数据转换为数值的方法
Jul 05 #Python
利用Python3分析sitemap.xml并抓取导出全站链接详解
Jul 04 #Python
在django中使用自定义标签实现分页功能
Jul 04 #Python
详解django中自定义标签和过滤器
Jul 03 #Python
pygame实现弹力球及其变速效果
Jul 03 #Python
[原创]使用豆瓣提供的国内pypi源
Jul 02 #Python
You might like
PHP远程采集图片详细教程
2014/07/01 PHP
简单实用的PHP文本缓存类实例
2019/03/22 PHP
php curl操作API接口类完整示例
2019/05/21 PHP
php多进程应用场景实例详解
2019/07/22 PHP
IE和FireFox(FF)中js和css的不同
2009/04/13 Javascript
基于jQuery替换table中的内容并显示进度条的代码
2011/08/02 Javascript
jquery 回车事件实现代码
2011/08/23 Javascript
分享一个自定义的console类 让你不再纠结JS中的调试代码的兼容
2012/04/20 Javascript
select、radio表单回显功能实现避免使用jquery载入赋值
2013/06/08 Javascript
JavaScript改变HTML元素的样式改变CSS及元素属性
2013/11/12 Javascript
jQuery操作Select的Option上下移动及移除添加等等
2013/11/18 Javascript
jQuery实现多按钮单击变色
2014/11/27 Javascript
js比较日期大小的方法
2015/05/12 Javascript
如何解决ligerUI布局时Center中的Tab高度大小
2015/11/24 Javascript
BootstrapTable与KnockoutJS相结合实现增删改查功能【一】
2016/05/10 Javascript
vue.js开发实现全局调用的MessageBox组件实例代码
2017/11/22 Javascript
使用Vue开发一个实时性时间转换指令
2018/01/17 Javascript
Angular整合zTree的示例代码
2018/01/24 Javascript
jQuery实现DIV响应鼠标滑过由下向上展开效果示例【测试可用】
2018/04/26 jQuery
Vue触发式全局组件构建的方法
2018/11/28 Javascript
vue写h5页面的方法总结
2019/02/12 Javascript
vue 使用 canvas 实现手写电子签名
2020/03/06 Javascript
python算法学习之基数排序实例
2013/12/18 Python
Linux中Python 环境软件包安装步骤
2016/03/31 Python
python使用tkinter库实现五子棋游戏
2019/06/18 Python
Django实现任意文件上传(最简单的方法)
2020/06/03 Python
css3的@media属性实现页面响应式布局示例代码
2014/02/10 HTML / CSS
Canvas与Image互相转换示例代码
2013/08/09 HTML / CSS
英国国家美术馆商店:National Gallery
2019/05/01 全球购物
什么是ESB?请介绍一下ESB?
2015/05/27 面试题
双语教学实施方案
2014/03/23 职场文书
2014年新生军训方案
2014/05/01 职场文书
基层党建工作汇报材料
2014/08/15 职场文书
委托书的样本
2015/01/28 职场文书
早恋主题班会
2015/08/14 职场文书
2016公司中秋节寄语
2015/12/07 职场文书