利用Lucene与Nutch构建简单的全文搜索引擎

文章地址php

 

1.简介

 

本次实现分为两个部分,第一个部分是利用Lucene构建一个全文的搜索引擎,另一部分则是利用Nutch实现一样的功能。因为Lucene并非一个能够直接运行的程序,且不具有爬虫和文档处理的功能,所以在这一部分利用到了Heritrix和HTMLParser这两个工具分别实现爬虫与HTML文档解析的功能。而使用Nutch的时候只须要一些简单的配置和安装就能够直接运行。最后还对这二者进行了一个简单的对比,说明其各自的特色和适应的范围。html

2.Lucene

2.1 爬虫的设计

因为Lucene不具有爬虫的功能,所以这里使用到了Heritrix这样的一个工具。咱们利用Heritrix爬取一个指定网站(如:南京大学信息管理学院官方网站)的内容,为了简单起见这里只爬去网页格式的文档,而“.doc/.xls/.ppt/.pdf”等格式的文件则直接忽略,所以这里还须要对爬虫进行一个简单的设计。
这里使用的Heritrix版本为Heritrix-1.14.4,爬虫的配置安装过程以下:
(1)源代码的导入
因为这里须要一些自定义的功能,所以使用的是Heritrix的源代码版本。为方便开发,首先咱们须要将其导入Myeclipse。在Myeclipse下创建一个工程名为“MyHeritrix”。
导入类库
这一步须要将 Heritrix-1.14.4-src 下的 lib 文件夹拷贝到 MyHeritrix 项目根目录;方法以下:在 MyHeritrix 工程上右键单击选择“Build Path Configure Build Path …”,而后选择 Library 选项卡,单击“Add JARs …”,在弹出的“JAR Selection”对话框中选择 MyHeritrix 工程 lib 文件夹下全部的 jar 文件,而后点击 OK 按钮。
拷贝源代码
将 Heritrix-1.14.4-src\src\java 下的 com、org 和 st 三个文件夹拷贝进 MyHeritrix 工程的 src 下。这三个文件夹包含了运行 Heritrix 所必须的核心源代码;将 Heritrix-1.14.4-src\src\resources\org\archive\util 下的文件 tlds-alpha-by-domain.txt 拷贝到 MyHeritrix\src\org\archive\util 中。该文件是一个顶级域名列表,在 Heritrix 启动时会被读取;将 Heritrix-1.14.4-src\src 下 conf 文件夹拷贝至 Heritrix 工程根目录。它包含了 Heritrix 运行所需的配置文件;将 Heritrix-1.14.4-src\src 中的 webapps 文件夹拷贝至 Heritrix 工程根目录。该文件夹是用来提供 servlet 引擎的,包含了 Heritrix 的 web UI 文件。
(2)源代码的修改
因为咱们须要一个功能:不爬取网页中的.doc/.xls/.ppt/.pdf等格式的文件,而是自定义须要爬取的网页文件,所以咱们须要自行修改程序。这里实现的方法为扩展 FrontierScheduler 来抓取特定网站内容。
FrontierScheduler 是org.archive.crawler.postprocessor 包中的一个类,它的做用是将在 Extractor 中所分析得出的连接加入到 Frontier 中,以待继续处理。在该类的 innerProcess(CrawlURI) 函数中,首先检查当前连接队列中是否有一些属于高优先级的连接。若是有,则马上转走进行处理;若是没有,则对全部的连接进行遍历,而后调用 Frontier 中的 schedule() 方法加入队列进行处理。这里咱们自行设计一个类FrontierSchedulerForDaven继承FrontierScheduler类来修改程序的功能:java

1
2
3
4
5
6
7
8
9
public class FrontierSchedulerForDaven extends FrontierScheduler
     而后在该类中重写schedule函数:
protected void schedule(CandidateURI caURI)
String uri=caURI.toString();
if (uri.indexOf( "dns:" )!=- 1 ){getController().getFrontier().schedule(caURI);} else
if (uri.indexOf(“nju.edu.cn ")!=-1)||uri.indexOf(" .html ")!=-1||uri.indexOf(" .php")!=- 1
||uri.indexOf( ".jsp" )!=- 1 ||uri.indexOf( ".asp" )!=- 1 ||uri.indexOf( ".shtml" )!=- 1 ))

经过这样的一个布尔表达式实现就能够实现只爬取后缀名为html、php、jsp、asp、shtml格式的文件,其余类型的文件一概忽略。
程序修改完成以后,在修改conf/modules/Processor.options文件,在该文件中添加以下一行:
1
(3)Heritrix启动与爬虫建立
在启动以前,咱们还须要对Heritrix进行一些简单的配置,找到conf/Heritrix.properties文件,在文件当中将Heritrix.cmdline.admin(用户名、密码)和Heritrix.cmdline.port(端口)两个参数修改成以下形式:
2
上面的配置表明,Heritrix启动时的端口为9999,用户名密码分别为admin和admin。
完成上面步骤以后,找到org.archive.crawler.Heritrix类,该类是Heritrix的主类入口,直接运行该类就能够启动Heritrix。启动成功以后,控制台会输出以下信息:
3
从上图能够看出,Heritrix内置了一个Jetty服务器,在浏览其启动的地址为:127.0.0.1:9999。在地址栏直接输入该地址就能够进入Heritrix的登陆界面。帐户名和密码为上面所设置的admin。
接下来就能够直接进入爬虫的建立过程,过程以下:在Job选项卡的create new job中选择with default即进入爬虫的建立界面:
4
上面所表单的第一行为爬虫的名称,第二行为对爬虫的描述,下面的文本框中输入爬虫的入口地址,例如:http://im.nju.edu.cn/。
(4)爬虫配置的修改与爬虫运行
在上面一步的基础上单击”modules”按钮,在相应的页面为这次任务设置各个处理模块,一共有七项可配置的内容:
1)Select Crawl Scope:Crawl Scope 用于配置当前应该在什么范围内抓取网页连接。例如选择 BroadScope 则表示当前的抓取范围不受限制,选择 HostScope 则表示抓取的范围在当前的 Host 范围内。在这里咱们选择 BroadScope。
2)Select URI Frontier:Frontier 是一个 URL 的处理器,它决定下一个被处理的 URL是什么。同时,它还会将经由处理器链解析出来的 URL 加入到等待处理的队列中去。
3)Select Pre Processors:这个队列的处理器是用来对抓取时的一些先决条件进行判断。好比判断 robot.txt 信息等,它是整个处理器链的入口。
4)Select Fetchers:这个参数用于解析网络传输协议,好比解析 DNS、HTTP 或 FTP 等。
5)Select Extractors:主要是用于解析当前服务器返回的内容,取出页面中的 URL,等待下次继续抓取。
6)Select Writers:它主要用于设定将所抓取到的信息以何种形式写入磁盘。一种是采用压缩的方式(Arc),还有一种是镜像方式(Mirror)。这里咱们选择简单直观的镜像方式。
7)Select Post Processors:这个参数主要用于抓取解析过程结束后的扫尾工做,好比将 Extrator 解析出来的 URL 有条件地加入到待处理的队列中去,这里咱们选择以前本身定义的类:org.archive.crawler.postprocessor.FrontierSchedulerForDaven
上面的7个参数,除了特别指出来的除外,其余的几个采用默认形式便可。
设置完“Modules”后,点击“Settings”按钮,这里只须要设置 user-agent 和 from,其中:“@VERSION@”字符串须要被替换成 Heritrix 的版本信息。“PROJECT_URL_HERE”能够被替换成任何一个完整的 URL 地址。“from”属性中不须要设置真实的 E-mail 地址,只要是格式正确的邮件地址就能够了。
当爬虫配置完成以后,就能够运行爬虫了,选择console选项卡,点击start就能够启动爬虫,爬虫运行过程当中的截图以下:
5
爬虫运行完成以后会在MyHeritrix/jobs文件夹下面生成一个Mirror文件夹,里面存放了爬去的的文件内容。web

2.2文档的预处理

在实际的应用当中,网站内会有大量除了网页文件以外的文件,例如ms office文件、pdf文件等等。而这些不一样的文件须要不一样的工具来进行处理,下面我总结了一些常见格式文档与其对应的解析工具:
文档类型 HTML Word Excel PPT RTF PDF
文档解析器 HTMLParser POI POI POI POI PDFBox
下面对上面所列举的工具进行一个简单的介绍:
(1)HTMLParser
HTMLParser是一个专门用来解析HTML格式文档的开源Java库,绝不夸张地说,HTMLParser就是目前最好的HTML解析和分析的工具,它的特色是快速健壮。其主要的功能有:
文本信息抽取,例如对HTML进行有效信息搜索
连接提取,用于自动给页面的连接文本加上连接的标签
资源提取,例如对一些图片、声音的资源的处理
连接检查,用于检查HTML中的连接是否有效
页面内容的监控
连接重写,用于修改页面中的全部超连接
网页内容拷贝,用于将网页内容保存到本地
内容检验,能够用来过滤网页上一些使人不愉快的字词
HTML信息清洗,把原本乱七八糟的HTML信息格式化
转成XML格式数据
在项目实施过程当中,我利用HTMLParser将一个HTML文档解析成三行,第一行为文档所对应的URL地址,第二行为文档的标题,第三行为文档的摘要。
第一行:URL
this.page.setURL(getURL(this.filename));
第二行:title
this.page.setTITLE(visitor.getTitle());
第三行:summary
this.page.setCONTEXT(combineNodeText(visitor.getBody().toNodeArray()));
而后将全部解析出来的文档存入另一个文件夹。该文件夹中的文件能够直接用于索引的构建。
(2)POI
POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式文档读和写的功能,它主要有五个模块,其名称和功能以下:
模块 功能
HSSF 提供读写Microsoft Excel格式档案的功能
XSSF 提供读写Microsoft Excel OOXML格式档案的功能
HWPF 提供读写Microsoft Word格式档案的功能
HSLF 提供读写Microsoft PowerPoint格式档案的功能
HDGF 提供读写Microsoft Visio格式档案的功能
因为这里不作MS OFFICE文档的解析,所以再也不详细解释其用法。
(3)PDFBox
PDFBox一样是Apache下的一个开源项目,专门用于PDF文档的解析。它容许在项目中利用程序设计语言建立PDF文档、操做多个PDF文档以及从PDF文档中解析出内容。
其主要的功能以下:从PDF文档中解析出内容;合并和分割PDF文档;PDF问的打印;将PDF文档转换为照片格式;PDF文档中表格的填充;PDF/A的验证;PDF文档的建立;与Lucene的整合开发。算法

2.3 索引的构建

索引的构建直接利用Lucene便可完成,索引中利用的分词工具为MMAnalyzer极易中文分词组件,为了获得更好的效果咱们可使用中科院的分词ICTCLAS,可是须要咱们自行编写分析器Analyzer,这里为了简单起见,利用了现成的中文分词工具MMAnalyzer。
建立索引的时候,首先须要建立IndexWriter,而后再建立的document,最后建立field来存放不一样部分的数据。在本实验中总共建立了4个域(fields),第一个域名称为”id”,用于标识一个文件;第二个为”url”,用于存放该文件所对应的URL;第三个域为”title”,用于存放该文件的标题,这个标题也被用做在搜索结果中的标题;第四个域为”context”,用于存放文本的内容,即搜索结果中的摘要部分。
具体的程序代码以下:apache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
IndexWriter writer= new IndexWriter(path, new MMAnalyzer()); //MMAnalyzer极易中文分词组件
reader= new BufferedReader( new FileReader(files[i]));
fields[ 0 ] = new Field( "id" ,String.valueOf(i),Field.Store.YES,Field.Index.NO);
fields[ 1 ]= new Field( "url" ,reader.readLine(),Field.Store.YES,Field.Index.NO);
fields[ 2 ]= new Field( "title" ,reader.readLine(),Field.Store.YES,Field.Index.TOKENIZED);
fields[ 3 ]= new Field( "context" ,getBodyFile(files[i].getAbsolutePath(),reader),Field.Store.YES,Field.Index.TOKENIZED);
//建立Document
Document doc= new Document();
//将五个field添加到doc中
for ( int j= 0 ;j<fields.length;j++)
{doc.add(fields[j]);}
//将Document添加到IndexWriter中
writer.addDocument(doc);
//优化和关闭
writer.optimize();
writer.close();
reader.close()

注意在建立完成field以后,经过document的add函数将field添加到document中,完成以后还要利用Indexwriter的addDocument函数将document添加到IndexWriter中。
最后一步不要忘了利用optimize和close函数来优化索引和关闭资源。
索引创建完成以后会在指定索引文件夹中生成四个文件:
_o.cfs/_w.cfs/segments.gen/segements_1f。
接下来就能够对这些索引文件进行检索了。数组

2.4查询实现

Lucene查询实现的方法主要有两种,第一种是Query,另一种是Queryparser,二者有明显的差异。QueryParer类用来转换用户的检索关键词,其做用就是把用户输入的非格式化检索词转换为后台检索能够理解的Query对象。用Queryparser时须要一个参数Analyzer,若是要进行分词处理的话就可能须要这个参数。
Query类是一个抽象类,须要使用Query的某个子类的构造函数来实例化并以此来表示与用户检索有关的内容。具体使用的时候,用户能够经过Query的一系列子类,如TermQuery/BooleanQuery/RangeQuery/PrefixQuery/PhraseQuery/MultiPhraseQuery/FuzzyQuery/WildcardQuery/SpanQuery/Regexuery的构造函数来直接生成对应的Query对象。这些检索方式各有其特色,经过命名大体能够猜想出它的功能,这里再也不作详细的介绍。
为了方便起见,实验中用的检索方式为TermQuery,这个检索方式只支持词的检索,所以须要在检索前将问句进行分词处理,而这里使用的分词工具为ICTCLAS。各个检索词之间采用的是布尔运算的“或”运算。浏览器

1
2
TermQuery[] term= new TermQuery[length];
query.add(term[i],BooleanClause.Occur.SHOULD); //经过后面参数肯定布尔检索类型

在Lucene中布尔检索中各运算符与其所对应的参数以下表:
运算类型 所对应的参数
AND(与) BooleanClause.Occur.MUST
NOT(非) BooleanClause.Occur.MUST_NOT
OR(或) BooleanClause.Occur.SHOULD
举例说明布尔或运算的运算规则,若是输入查询词“信息”和“管理”,查询结果为包含“信息”与“管理”这两个词的文档与只包含“信息”这个检索词的文档以及只包含“管理”这个词的文档。固然在实际的操做中能够采用彻底不一样的查询方式。
下面为ICTCLAS的分词过程:tomcat

1
2
3
4
5
6
7
8
9
10
11
public String[] getParserResult(ICTCLAS instance,String sentence){
   String result;
   result=instance.paragraphProcess(sentence);
   String[] res;
   res=result.split( "\\s+" );
   for ( int i= 0 ;i<res.length;i++){
   int position=res[i].indexOf( "/" );
   System.out.println(position);
   res[i]=res[i].substring( 0 , position);
   System.out.println(res[i]); }
return res;}

这里对上面的程序进行一个简单的介绍,其中最重要的一行为:
result=instance.paragraphProcess(sentence);
其中sentence表明输入的问句,result就是通过分词获得的结果,不过输出结果形式有一个特别之处,例如:句子“信息检索”其result的结果形式为“信息/n 检索/v”,而在实际的过程当中咱们并不须要后面的词性以及”/”,所以后面的程序代码都是为了将分词结果变成一个字符数组,去掉空格以及后面的”/”和词性。
分词完成以后就能够把分词结果放入term中进行检索了。服务器

2.5界面实现

界面部分须要两个文件一个index.html文件,一个是search.jsp文件,其中index.html主要做用是查询主界面的实现。而search.jsp则用户处理问句、问句检索以及检索结果展现。
下面是index.html文件的表单部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     <form action= "search.jsp" method= "GET" >
     <input type= "text" name= "keys" size= 50 height=100px class =kw maxlength= "100" >
     <input type= "submit" value= "search" class =sb>
     <font size= "2" face= "宋体" >
能够看到其表单的内容其实都交给了search.jsp来处理。而search.jsp的部分代码以下:
     <jsp:directive.page import = "com.davenzhang.util.*" />
     <jsp:directive.page import = "com.xjt.nlp.word.ICTCLAStest" />
     ……
     <form action= "search.jsp" method= "get" >
     <input type= "text" name= "keys" size= 36 maxlength= "100" >
     <input type= "submit" value= "search" >
     <a href= "index.html" >Home</a>
     ……
     out.println( "<font size=4px color=\"blue\">" +title+ "</font><br>" );
     out.print( "摘要:" +summary);
     out.print( "<br><a href=http://" +url+ "><font color=\"green\">" +url+ "</font></a> <br>" );

前面的import部分,是导入一些java包,方便在jsp代码中直接使用其功能,com.davenzhang.util.*主要包含了Lucene的查询函数,而com.xjt.nlp.word.ICTCLAStest包则包含分词所用到的函数。后面的out.println()则用于查询结果的展现

3.Nutch

3.1 Nutch安装与配置

与Lucene不一样,Nutch是一个能够直接运行的程序,基本上不须要本身编写任何代码就能实现简单的全文搜索引擎的功能。下面介绍Nutch的安装和配置过程。
(1) 安装JDK/Tomcat/Cygwin,这些软件的安装都有详细的教程,这里再也不赘述。
(2) 修改环境变量
变量名 NUTCH_JAVA_HOME
变量值 %JAVA_HOME%
运行cygwin,输入命令cd /cygdrive/d/ Nutch-1.2,再输入bin/Nutch,若是出现Nutch的命令行介绍就表明Nutch安装成功。
6

(3) 爬虫设置
与Lucene不一样,Nutch自带了爬虫的功能,可是须要进行一些配置,下面对这个过程作一个详细的介绍。
设置须要抓取的网站主域名
在Nutch-1.2的安装目录下创建一个名为urls的文件夹,并在文件夹下创建url.txt文件,在文件中写入口地址http://im.nju.edu.cn/
设置网站过滤规则
编辑conf/crawl-urlfilter.txt文件,修改MY.DOMAIN.NAME部分。将
# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*MY.DOMAIN.NAME/
改成:
# accept hosts in MY.DOMAIN.NAME
+^http://([a-z0-9]*\.)*nju.edu.cn/
修改conf/Nutch-site.xml代理信息
在和之间添加以下文件:

http.agent.name
http://im.nju.edu.cn/value> http.agent.url
http://im.nju.edu.cn/value> http.robots.agents
http://im.nju.edu.cn/ 设置代理名
编辑Nutch-1.2\conf\Nutch-default.xml文件,找http.agent.name,而后随便设置Value值。例如:

 

http.agent.name
test
执行Nutch抓取url数据
在Cygwin命令行窗口中输入:cd /cygdrive/d/Nutch-1.2
再输入bin/Nutch crawl urls –dir crawl –depth 3 –threads 4 –topN 30 >& crawl.log
命令说明:
crawl:是Nutch检索数据命令,后面跟上要检索的URL文件。urls就是第一部分部份建立的文件;
-di:是检索后的结果存放目录参数,后面跟上结果存放地址。若是咱们存放到Nutch目录下的crawl目录,注意此目录当前是不存在的。检索完后Nutch会建立出来。-threads 抓取时的线程数参数
-depth:抓取时的深度参数
-topN:抓取时每页的最大抓取连接
最后把执行信息写入crawl.log日志文件中,方便查找错误。
爬虫执行完成以后会在Nutch的目录下生成一个crawl文件夹,里面包含五个子文件夹,分别为:crawldb/index/indexes/linkdb/segments。
部署到Tomcat
将Nutch-1.2目录下的Nutch-1.2.war复制到Tomcat目录webapp下面
修改配置文件WEB-INF\classes\Nutch-site.xml为以下形式,其中的value值就是刚才爬虫爬取得信息。

 

7

而后重启tomcat就能够完成Nutch的安装于配置的所有过程。

3.2Nutch的运行

在浏览器中输入http://localhost:8080/Nutch-1.2/zh/,便可进入Nutch主页面,输入检索词“南京大学”所获得的检索结果以下图所示:
8
下面是Nucth的一些特性:
默认把词语分红单个词来查询,例如,“计算机”会以“计”、“算”、“机”来作查询。
Nutch中全部的parsing(分析)、indexing(索引)和searching(查询)都是经过不一样的插件来实现的。Nutch把本身能够提供的Plugin接口用一个xml文档来描述。
自定义插件时,只须要自行设计一些符合自身功能需求的类(继承Nutch提供的父类或者实现一些接口),而后修改配置文件就好了。

4.Lucene与Nutch对比

Lucene实际上是一个提供全文文本搜索的函数库,它不是一个应用软件。它提供不少API函数让你能够运用到各类实际应用程序中。如今,它已经成为Apache的一个项目并被普遍应用着。Lucene无论是爬虫的设计,仍是文档的预处理,仍是索引的创建,仍是系统的分词等等,都须要用户编写代码,实现功能。Lucene给用户提供了很是强大的功能,但要享受这些功能的则必须具有编写复杂代码的能力。不管是在爬虫的选择、搜索的优化、排序算法的设计等等用户都须要自行决定。
Nutch是一个创建在Lucene核心之上的Web搜索的实现,它是一个真正的应用程序。也就是说,你能够直接下载下来拿过来用。它在Lucene的基础上加了网络爬虫和一些和Web相关的东西。其目的就是想从一个简单的站内索引和搜索推广到全球网络的搜索上。Nutch主要分为两个部分:爬虫crawler和查询searcher。Crawler主要用于从网络上抓取网页并为这些网页创建索引。Searcher主要利用这些索引检索用户的查找关键词来产生查找结果。二者之间的接口是索引,因此除去索引部分,二者之间的耦合度很低。Crawler和Searcher两部分尽可能分开的目的主要是为了使两部分能够分布式配置在硬件平台上,例如将Crawler和Searcher分别放在两个主机上,这样能够提高性能。
另外,还有一个和Lucene相似的工具Solr。Solr是Lucene的服务器化,内嵌了jetty,用户能够直接post数据给Solr,而后由Solr进行索引。Solr不包含下载系统,用户须要负责下载,转成Solr所须要的格式。Nutch和Solr都是基于Lucene的,两者都是可直接运行的应用程序。 通常可使用Nutch作crawler,而使用Solr作indexer和查询接口。

参考文献:
[1]. Otis Gospodnetic;Erik Hatcher(著). lucene in action(中文版).谭鸿;黎俊鸿等译.北京:电子工业出版社, 2007
[2]. 罗刚.解密搜索引擎技术实战:Lucene&Java精华版. 北京:电子工业出版社,2011
[3]. 袁津生, 李群主编.搜索引擎基础教程.北京:清华大学出版社, 2010
[4]. 高凯,郭立炜,许云峰编著.网络信息检索技术及搜索引擎系统开发.北京:科学出版社, 2010
[5]. http://lucene.apache.org/
[6]. http://nutch.apache.org/
[7]. http://crawler.archive.org/index.html
[8]. http://sourceforge.net/p/htmlparser/wiki/Home/
[9]. http://pdfbox.apache.org/
[10]. poi

相关文章
相关标签/搜索