Advertisement

python全文检索引擎_用python做一个搜索引擎(Pylucene)

阅读量:

什么是搜索引擎?

搜索引擎负责对网络中的各种信息资源进行搜集、整理,并为用户提供高效的信息检索服务。主要包含三个核心功能:信息搜集、信息整理以及用户查询。其中,信息搜集模块负责从网络中采集各类有用的信息并存入数据库中(一般采用爬虫技术进行抓取)。随后由信息整理模块对其进行分词处理、去除无意义词汇并对重要性进行评分以建立索引表(通常采用倒排索引结构)。最后通过用户的查询接口使其能够识别用户的检索需求并实现相应的信息服务功能。

818605-20170704162314144-296050834.png

图1 搜索引擎的一般结构

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

2.1 问题分析

通过查看图1可知,一套完整的搜索引擎架构始于从互联网上获取信息的过程。可以通过Python开发一个爬虫脚本(即爬虫),这体现了Python的强大功能。

接着,在数据预处理模块中进行操作。具体来说就是对信息进行分词处理、去除停用词以及构建倒排表等基础工作。对于那些看似杂乱无章的字段名和字段值(即"what"?"什么乱七八糟的字段名和字段值?"),我们无需过多纠结于细节(因为这些工作都是已有解决方案可解决的问题)。我们可以借助现有的工具框架(如Pylucene)来完成这些任务:Pylucene是一个将Lucene搜索引擎技术封装成Python接口的开源工具包。通过使用Pylucene我们能够便捷地完成对采集到的信息数据进行组织与管理(包括建立索引并实现高效的搜索功能)。

最终,在需要将我们的搜索引擎应用于网页环境中时

2.2 爬虫设计

主要收集的内容包括目标网页的标题、正文内容以及指向其他页面的URL地址。如图2所示,网络爬虫的工作流程主要依赖于一种称为"队列"的数据结构。具体而言,在爬虫运行过程中会执行以下步骤:首先将初始种子节点加入队列中;然后不断从队列中取出一个节点进行访问;对于每个被访问过的节点页面,在其内容分析后会获取并记录所有包含的目标信息;同时将该页面包含的所有链接信息添加到队列中;接着继续从新的节点开始重复上述操作;直到整个队列为空为止。通过采用"先进先出"原则实现了广度优先搜索算法的基础上完成对各个站点所有页面的一次性访问

818605-20170704162409956-2118302175.png

图2

2.3 pylucene的使用

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

该软件库中的一个核心组件是一个名为directory的功能模块,在其内部实现了多种文件操作功能的具体实现方案,并通过继承的方式为这些功能提供统一的基础支持体系架构。在这一模块中定义了多个派生类型对象来实现特定功能需求,并通过继承的方式为这些功能提供统一的基础支持体系架构。其中包含了SimpleFSDirectoryRAMDirectory以及CompoundFileDirectoryFileSwitch Directory等多种类型的派生实例对象,在实际应用过程中可以根据具体需求灵活选择合适的功能模块组合来满足实际应用中的各种特定需求。

Analyze类是一个用于接收并处理即将参与索引构建的文字内容的分词工具。该类具体实现了对文本的分词、去除非必要词汇以及统一大小写的功能。Pylucene内置了几种预定义的分析工具,并允许用户根据需求选择第三方库提供的工具或自定义解决方案。不同版本或定制化的分析器直接影响着索引质量以及搜索结果准确性和响应速度。

该类用于管理与目录相关的索引信息。
当 Directory 创建时,在其内部存储空间中该类将负责对相关数据进行管理,并支持对索引信息进行增删改等基本操作。
不允许对该目录下的现有数据执行读取或搜索操作。

在Pylucene系统中将文档定义为基本单元(Document)。每一个Document可以代表一个网页一篇文章或者一封邮件等具体内容。作为构建索引的核心单元同时也是检索结果的基础单位合理优化每个Document的设计能够有效提升搜索引擎的服务质量并满足个性化需求

File类。一个Document中可以包含多个Field(字段)。File是Document的一个组成部分,类似于一篇文章是由文章标题、正文内容、作者信息、发布日期等多个部分组成的。每一个File都代表了Document中的一个特定领域或数据项,并构成了Document的整体架构

将一个页面定义为Document对象,并包含三个字段:一个是页面的URL地址(url),一个是页面标题(title),一个是主要文字内容(content)。采用SimpleFSDirectory类来管理索引,并将其存储至指定文件中。选择Pylucene内置模块中的CJKAnalyzer作为分析器,在中文文本处理方面效果较为显著。

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

lucene.initVM()

INDEXIDR = self.__index_dir

indexdir = SimpleFSDirectory(File(INDEXIDR))①

analyzer = CJKAnalyzer(Version.LUCENE_30)②

writer = IndexWriterFunction(indexdir, AnalyzerInstance, true, IndexWriterFunction.MaxFieldLength(512))③

document = Document()④

document包含Fields("内容字段", "字符串表示的内容字段", "NOT存储类型", "AANLYzed索引类型")⑤

在文档中字段'url'处使用visiting值,并将其字段设置为Store.YESto,并在索引中标记为Index.NA

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时,则表示生成新的索引。其中MaxFieldLength属性决定了最大字段数(Field数量)。

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

在Markdown文档中添加一个字段项名为"content"

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

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

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]。

Index Searcher是一个索引搜索工具类,在基于IndexWriter构建的索引库中执行搜索操作

该类用于描述并执行查询请求,并将接收并传递给IndexSearcher以完成搜索操作。该类包含多种子类以便处理不同类型的查询需求。例如TermQuery用于按词条进行搜索,在指定字段内检索特定文档;RangeQuery在指定范围内执行查找;而FuzzyQuery则是一种模糊类型查询,在一定程度上识别与关键字语义相近的近义词进行匹配。

Query解析器QueryParser。当需要处理多种查询需求时,则需使用Query提供的不同子类这使得在使用时容易产生混淆因而Pylucene还提供了一个基于查询语法规则的解析器QueryParser。该解析器能够将提交的查询语句按照预定义的规则进行分解并映射到相应的查询子类上从而实现高效的查询处理过程例如对于关键字1和关键字2这样的查询语句其解析结果是同时匹配这两个关键字的所有文档对于id域中的值范围在123到456之间的文档则会被解析为匹配特定条件进而返回相应的搜索结果最后对于包含site字段限制条件如site:www.web.com这类复杂查询也能得到准确的响应确保系统运行效率的同时提高用户体验

Pylucene专注于领域中的索引搜索。为此目的,创建了一个用于实现索引搜索 named 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'对应的值是result_urls元组键为'title'对应的值是result_titles元组

return result

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

在处理搜索语句时,在以下两种情况下,默认同时检索 title content 两个领域:第一种情况是当搜索语句未专注于单一领域(如 title 或正文);第二种情况是当不包含关键词" title: "或" content: "时。

请生成一个名为SimpleFSDirectory的对象,并将其工作目录设置为之前创建索引的位置。

创建一个CJKAnalyzer分析器的实例,在搜索过程中应用的分析器必须与在索引构建过程中应用的分析器在类型版本上完全一致。

创建一个IndexSearcher对象lucene_searcher,并将其参数设置为第○2步生成的SimpleFSDirectory对象。

创建一个QueryParser对象my_query用于描述用户的查询请求并解析其对应的Query类型查询语句。该对象将使用以下参数配置:Version.LUCENE_CURRENT指定当前使用的pylucene版本号,默认情况下会关注'title'字段;'lucene_analyzer'字段则决定了使用的分析器类型;变量query_str即表示用户的Query(查询)语句。在配置此对象之前会执行一些简单的预处理操作:如果用户提供明确指定要检索的具体领域,则仅在此领域内执行搜索操作;若无具体指示,则将同时在默认字段(如'title')以及内容字段上展开搜索以获取结果集信息。

lucene_searcher执行搜索操作,并返回结果集合total_hits。total_hits集合中包含以下信息:总记录数totalHits、搜索结果所在的数据库scoreDocs。其中总记录数totalHits表示总共有多少条记录;scoreDocs是一个集合数据库中的数据;每个记录包括匹配到的文档及其与查询语句的相关性评分。

Lucene_searcher执行完查询后得到的结果集合无法直接在Python环境中操作,在获取所有搜索结果后才进行格式转换工作。可以通过遍历每个查询结果并按照相关性排序后提取每个文档的URL信息存入列表result_urls中,并收集标题信息存入列表result_titles中。最后整合所有信息形成一个包含地址与标题信息的字典对象作为最终返回数据

当用户在浏览器的查找框中输入查询项并按回车键时

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

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

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

def index():

html="

title这是标题

"

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 the template of 'result.html' with the parameters: key_word, result_sum(re["Hits"]), and so_result

else:

key_word=""

return render_template('result.html')

if name == 'main':

app.debug = True

app.run()#运行web服务

原文:https://www.cnblogs.com/lucky-pin/p/7117182.html

全部评论 (0)

还没有任何评论哟~