利用开源工具构建小型搜索引擎项目报告.
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
深圳大学考试答题纸
(以论文、报告等形式考核专用)
二○~二○学年度第学期
课程编号1501320002 课程名称搜索引擎技术主讲教师王旭评分
学号姓名专业年级
题目:利用开源工具构建小型搜索引擎
一、项目操作环境及基本操作工具:
操作系统:Win10。
基本操作环境:基于Heritrix+ Lucene;java。
基本操作工具:JDK 1.8,MyEclipse Professional 2014,Tomcat 8.0.27,Heritrix 1.14.4,Lucene 2.1.0,— JE-analysis-1.5.3, Htmlparser 1.5。
基本操作工具基本功能介绍:
JDK 1.8:JDK(Java SE Development Kit)包括Java开发包和Java开发工具,是一个写Java 的applet和应用程序的程序开发环境。
它由一个处于操作系统层之上的运行环境还有
开发者编译,调试和运行用Java语言写的applet和应用程序所需的工具组成。
MyEclipse Professional 2014: Eclipse是一种可扩展的开放源代码IDE。
2001年11月,IBM公司捐出价值4,000万美元的源代码组建了Eclipse联盟,并由该联盟负责这种工具的后
续开发。
集成开发环境(IDE)经常将其应用范围限定在“开发、构建和调试”的周期
之中。
为了帮助集成开发环境(IDE)克服目前的局限性,业界厂商合作创建了Eclipse
平台。
MyEclipse,是在eclipse 基础上加上自己的插件开发而成的功能强大的企业级集
成开发环境。
Tomcat 8.0.27:—Tomcat服务器是一个免费的开放源代码的Web 应用服务器,它是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、
Sun 和其他一些公司及个人共同开发而成。
—Tomcat 8支持最新的Servlet 3.1 和JSP 2.3 规范。
因为Tomcat技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并
得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。
Heritrix 1.14.4:Heritrix是一个开源、可扩展的Web爬虫项目。
Heritrix设计成严格按照robots.txt 文件的排除指示和META robots标签。
Lucene 2.1.0:—Lucene是Apache软件基金会jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方
语言)。
JE-analysis-1.5.3:是一个免费的Lucene中文分词组件。
Htmlparser 1.5:是一个纯的java写的html解析的库,Htmlparser不依赖于其它的java库,Htmlparser主要用于改造或提取html。
二、该搜索引擎系统的基本构架:
先通过爬虫爬取原始网页并进行网页搜集;然后进行网页预处理;接着建立索引indexs;最后进行查询服务。
三、具体搭建和配置过程及问题分析:
(1)基本工具的安装:
a、JDK1.8的安装:
并配置环境变量:
JA V A_HOME:C:\Program Files\Java\jdk1.8.0_66
JRE_HOME:C:\Program Files\Java\jre1.8.0_66
CLASSPATH:%JA V A_HOME%\jre\lib\rt.jar;.;
PA TH:%JA V A_HOME%\jre\lib\rt.jar;.;
b、MyEclipse的安装:运行.exe文件
c、Tomcat的安装:解压安装;
设置环境变量:CATALINE_HOME:D:\big work\an zhuang\apache-tomcat-8.0.30;
设置好之后,测试一下Tomcat。
打开Bin文件夹,运行startup.bat;
打开浏览器,输入http://localhost:8080(或者http://127.0.0.1:8080),如果看到下图所示的界
面,表明Tomcat运行正常:
d、其他工具解压即可。
(2)Heritrix工程的建立:
a、解压Heritrix-1.14.4和Heritrix-1.14.4-src文件,
b、新建项目工程Heritrix:
c、配置该工程:
1、将Heritrix-1.14.4和Heritrix-1.14.4-src文件从上述网站中下载。
2、将文件中的lib放入工程中,右键工程->build path->configure build path->add external jars,
将lib中所有jar包添加到library中。
3、将文件中src\java\的org和st两个文件夹放到工程文件的src目录下。
4、将src\conf\下的所有文件及其文件夹拖至工程文件下,修改heritrix.properties中的
heritrix.version=1.14.4; heritrix.cmdline.admin=admin:admin,这是分别是版本号和登录所需要的用户(左)和密码(右)。
5、将src下除了conf和java以外的所有文件夹,拖至工程文件目录下。
6、运行run,成功时会显示版本:
7、创建好的Heritrix目录结构如下:
d、网页搜集:
1、扩展Heritrix:
新建一个类,叫FrontierSchedulerForScu,派生于org.archive.crawler.postprocessor.
FrontierScheduler,它的代码如下:
屏蔽zip、rar、exe文件,只抓取网页,并且抓取的网页中必须包含scu(即四川大学)
打开文件conf\modules\Processor.options
— 添加新建的module选项:
— org.archive.crawler.postprocessor.FrontierSchedulerForSzu|FrontierSchedulerForScu:
取消robots.txt的限制:找到org.archive.crawler.prefetch中的PreconditionEnforcer类: 找到considerRobotsPreconditions函数,将该函数内的全部代码注释掉或者直接删除添上return false:
f、网页抓取:
1、登录Heritrix:运行Tomcat后登录http://localhost:8080(或者http://127.0.0.1:8080)
2、Heritrix的控制台如下:
3、设置seed:设置为四川大学的URL
Select Crawl Scope选择org.archive.crawler.scope.BroadScope:
抓取网页后会生成镜像文件便于查看:
Select Post Processors第三项修改为org.archive.crawler.postprocessor.FrontierSchedulerForScu
其他设置如图:
5、参数设置:
—点击Settings ,这里只需要修改user-agent 和from :@VERSION@表示版本,后面的URL 输入/。
Email 也同样是输入一个有效的email 。
—设置好之后,点击Submit Job ,返回Console 界面,刷新一下(start 和refresh ),就开始运 行:如图可得到一下的进度条:
6、最终抓取的到的结果在工作区间的Heritrix下的jobs文件夹中:
共抓取约13万个文件。
(3)进行网页预处理:
a、添加htmlparser解析网页:
将下载的htmlparser相关的压缩包解压,找到htmlparser.jar文件,将至导入library中。
b、添加解析网页文件:Page.java:代码如下:
c、对Config.properties进行配置:
mirror.path是得到的网页文件的地址:
D:\bigwork\Heritrix_Lucene-20151208\Heritrix-1.14.4\jobs\ sichuan-university-20151223130135337
files.path是将网页文件解析后存放的文件地址;
Index.path是网页解析文件建立得到的索引的存放地址。
d、添加文件Extractor.java
代码如下:
package .szu.search.extractor;
import org.htmlparser.*;
import org.htmlparser.util.*;
import org.htmlparser.visitors.*;
import org.htmlparser.nodes.*;
import org.htmlparser.tags.*;
import .szu.search.page.*;
import .szu.search.util.*;
public class Extractor implements Runnable{
private String filename;
private Parser parser;
private Page page;
private String encode;
public void setEncode(String encode) {
this.encode = encode;
}
private String combineNodeText(Node[] nodes) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < nodes.length; i++) {
Node anode = (Node)nodes[i];
String line = null;
if (anode instanceof TextNode) {
TextNode textnode = (TextNode)anode;
line = textnode.getText();
}
else if (anode instanceof LinkTag) {
LinkTag linknode = (LinkTag)anode;
line = linknode.getLinkText();
}
else if (anode instanceof Div) {
if (anode.getChildren() != null) {
line = combineNodeText(anode.getChildren().toNodeArray());
}
}
else if (anode instanceof ParagraphTag) {
if (anode.getChildren() != null) {
line = combineNodeText(anode.getChildren().toNodeArray());
}
}
else if (anode instanceof Span) {
if (anode.getChildren() != null) {
line = combineNodeText(anode.getChildren().toNodeArray());
}
}
else if (anode instanceof TableTag) {
if (anode.getChildren() != null) {
line = combineNodeText(anode.getChildren().toNodeArray());
}
}
else if (anode instanceof TableRow) {
if (anode.getChildren() != null) {
line = combineNodeText(anode.getChildren().toNodeArray());
}
}
else if (anode instanceof TableColumn) {
if (anode.getChildren() != null) {
line = combineNodeText(anode.getChildren().toNodeArray());
}
}
if (line != null) {
buffer.append(line);
}
}
return buffer.toString();
}
private String getUrl (String filename) {
String url = filename;
url = url.replace(ProperConfig.getValue("mirror.path")+"/mirror", "");
if (stIndexOf("/") == url.length()-1) {
url = url.substring(0,url.length()-1);
}
url = url.substring(1);
return url;
}
private int getScore(String url, int score) {
String[] subStr = url.split("/");
score = score - (subStr.length-1);
return score;
}
private String getSummary(String context) {
if (context == null) {
context = "";
}
return MD5.MD5Encode(context);
}
public void extract(String filename) {
System.out.println("Message: Now extracting " + filename);
this.filename = filename.replace("\\", "/");
run();
if (this.page != null) {
PageLib.store(this.page);
}
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
parser = new Parser(this.filename);
parser.setEncoding(encode);
HtmlPage visitor = new HtmlPage(parser);
parser.visitAllNodesWith(visitor);
page = new Page();
// get page's URL
System.out.println(this.filename);
System.out.println(getUrl(this.filename));
this.page.setUrl(getUrl(this.filename));
System.out.println(this.page.getUrl());
// get page's title
String textInPage = visitor.getTitle();
System.out.println(textInPage);
this.page.setTitle(textInPage);
// testing <body> is null or not, if null, un-extracting
if (visitor.getBody() == null) {
this.page.setContext(null);
}
else {
// if have value, extracting
this.page.setContext(combineNodeText(visitor.getBody().toNodeArray()));
}
// count page's score
this.page.setScore(getScore(this.page.getUrl(), this.page.getScore()));
// count page's summary
this.page.setSummary(getSummary(this.page.getContext()));
}catch (ParserException pe) {
this.page = null;
pe.printStackTrace();
System.out.println("Continue...");
}
}
}
e、PageLib.java文件:
f、ProperConfig.java文件,代码如下:
g、MD5.java文件,代码如下:
h、TestExtractor.java测试类文件:
(4)建立索引:
1、 将lucene的jar包和je分词的jar包导入到Project当中,导入方法同前边章节所示的htmlparser
的导入方法,导入成功后,再新建一个包,命名为.scu.search.index。
— 2、添加一个新的类,叫作IndexBuilder。
package .szu.search.index;
import org.apache.lucene.document.*;
import org.apache.lucene.index.*;
import jeasy.analysis.*;
import java.io.IOException;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.File;
// create index class
public class IndexBuilder {
IndexWriter writer;
public IndexBuilder(String path) throws IOException {
writer = new IndexWriter(path, new MMAnalyzer());
}
public void build(String path) throws IOException {
BufferedReader reader = null;
File[] files = new File(path).listFiles();
for(int i = 0; i < files.length; i++) {
System.out.println(".");
reader = new BufferedReader(new FileReader(files[i]));
Document doc = new Document();
Field[] fields = new Field[5];
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("score", reader.readLine(), Field.Store.YES, Field.Index.NO);
fields[4] = new Field("context", getBodyFile(files[i].getAbsolutePath(), reader),
Field.Store.YES, Field.Index.TOKENIZED);
// create Document
for(int j = 0; j < fields.length; j++) {
doc.add(fields[j]);
}
// write Document into IndexWriter
writer.addDocument(doc);
}
writer.optimize();
writer.close();
reader.close();
}
private String getBodyFile(String path, BufferedReader reader) throws IOException {
StringBuffer buffer = new StringBuffer();
String line = reader.readLine();
while (line != null) {
buffer.append(line);
line = reader.readLine();
}
return buffer.toString();
}
}
— 3、定义一个新的类叫做TestIndexer,将之前所定义的所有类运转起来。
测试建立索引的类函数:
4、运行TestExtractor.java,生成文件储存在files文件中;
运行TestIndexer.java,生成索引。
运行后生成的文件如下:
处理后的文件:
生成的索引文件如下:
(5)进行查询服务:
1、search-engine配置:—
后台部分只涉及到一个类,就是Query,它负责根据关键字查询,并将查询结果返回。
— Query中包含了三个成员属性,第一个属性用来保存索引文件所在的位置。
第二个属性是一个Lucene中的查询对象,叫做IndexSearcher。
第三个是Lucene中的代表某一种查询方法的对象,叫做BooleanQuery。
最重要的是IndexSearcher,它能够根据定义的查询方式,从Lucene创建的索引中获得符合查询条件的数据,数据以Document对象返回。
2、页面设计:
a、搜索结果页面s.jsp: 由于搜索页面需要动态变化,用动态页面jsp
b、主页index.html: 由于主页并不需要“动”,用静态页面html:
c、查询主页面:
四、测试搜索引擎:
搜索界面如下:
搜索学院:
结果如下:
五、主要出现的问题及解决方法:
1、没有设置环境变量JRE_HOME和8080端口被其他程序占用,解决方法如下:
设置环境变量JRE_HOME:C:\Program Files\Java\jre1.8.0_66
在命令框输入cmd然后输入netstat -aon | findstr”8080”找出占用程序然后在dos把该
程序关了,再次运行Tomacat即可成功。
2、运行Query.java文件时出现HTTP Status 500 - /search-engine错误,解决方法:
原因是没有修改Config.properties中files和indexs以及job文件的地址,或者Query.java中
“/”打成了“\”,修改后即可成功运行。
3、运行Query.java 文件时出现HTTP Status 404 - /search-engine错误,解决方法:
多次运行Testindexer.java后出现的错误,所以将indexs源文件的索引删除后重新运行,即可
运行成功。
4、Tomcat运行后对爬虫设置时Modules中没有多余的可选选项,解决方法:
将Heritrix源文件中的conf文件夹目录下的modules文件夹复制到src目录下即可解决。
5、爬虫抓取文件时乱抓网页并没有按照应该抓的域去抓,解决方法:
设置Modules时在Select Post Processors选项中应该把第三项换成
Org.archive.crawler.postprocessor.FrontierSchedulerForSzu
六、项目感想:
本次项目让本人在很大程度上了解到搜索引擎的基本构架以及基本原理以及基于Heritrix和Lucense的开源搜索引擎的基本工具的使用,对于在以后的更进一步的学习将会有很大的帮助。
同时也培养了个人在搜索引擎方面的兴趣,激起了学习的欲望,拓宽了个人的知识面同时学到很多编程知识,受益匪浅。