用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第三方库xlrd/xlwt的安装与读写Excel表格
Jan 21 Python
使用Python实现windows下的抓包与解析
Jan 15 Python
tensorflow实现简单逻辑回归
Sep 07 Python
使用Python爬虫库requests发送请求、传递URL参数、定制headers
Jan 25 Python
Pycharm 安装 idea VIM插件的图文教程详解
Feb 21 Python
python实现贪吃蛇双人大战
Apr 18 Python
Python unittest基本使用方法代码实例
Jun 29 Python
python实现二分查找算法
Sep 18 Python
Python3.8.2安装包及安装教程图文详解(附安装包)
Nov 28 Python
详解numpy1.19.4与python3.9版本冲突解决
Dec 15 Python
Python+Appium实现自动化清理微信僵尸好友的方法
Feb 04 Python
Python实现对齐打印 format函数的用法
Apr 28 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
对text数据类型不支持代码页转换 从: 1252 到: 936
2011/04/23 PHP
thinkphp实现数组分页示例
2014/04/13 PHP
laravel5.2实现区分前后台用户登录的方法
2017/01/11 PHP
PHP实现Snowflake生成分布式唯一ID的方法示例
2020/08/30 PHP
百度 popup.js 完美修正版非常的不错 脚本之家推荐
2009/04/17 Javascript
jQuery 白痴级入门教程
2009/11/11 Javascript
一些经常会用到的Javascript检测函数
2010/05/31 Javascript
基于jQuery的Tab选项框效果代码(插件)
2011/03/01 Javascript
JQuery拖动表头边框线调整表格列宽效果代码
2014/09/10 Javascript
Js为表单动态添加节点内容的方法
2015/02/10 Javascript
jQuery基于ID调用指定iframe页面内的方法
2016/07/06 Javascript
打造自己的jQuery插件入门教程
2016/09/23 Javascript
JS实现移动端实时监听输入框变化的实例代码
2017/04/12 Javascript
详解nodejs实现本地上传图片并预览功能(express4.0+)
2017/06/28 NodeJs
基于 Bootstrap Datetimepicker 联动
2017/08/03 Javascript
Vue组件之全局组件与局部组件的使用详解
2017/10/09 Javascript
基于Node的Axure文件在线预览的实现代码
2019/08/28 Javascript
nuxt 自定义 auth 中间件实现令牌的持久化操作
2020/11/05 Javascript
[00:32]2018DOTA2亚洲邀请赛Liquid出场
2018/04/03 DOTA
Python获取apk文件URL地址实例
2013/11/01 Python
在Python中使用__slots__方法的详细教程
2015/04/28 Python
Python连接mysql数据库的正确姿势
2016/02/03 Python
Python实现一个服务器监听多个客户端请求
2018/04/12 Python
Python编写一个优美的下载器
2018/04/15 Python
Python八大常见排序算法定义、实现及时间消耗效率分析
2018/04/27 Python
python flask几分钟实现web服务的例子
2019/07/26 Python
解决tensorflow读取本地MNITS_data失败的原因
2020/06/22 Python
如何利用python读取micaps文件详解
2020/10/18 Python
HTML5 新事件 小结
2009/07/16 HTML / CSS
Answear匈牙利:来自全球200多个知名时尚品牌
2017/04/21 全球购物
Hunkemöller瑞士网上商店:欧洲最大的内衣品牌之一
2018/12/03 全球购物
艺校音乐专业自我鉴定范文
2014/03/01 职场文书
六五普法规划实施方案
2014/03/21 职场文书
我爱我家教学反思
2014/05/01 职场文书
python munch库的使用解析
2021/05/25 Python
日本动漫十大公认神作:第五现已全网禁播,《死亡笔记》在榜
2022/03/18 日漫