摘 要
通过搜索引擎从互联网上获取有用信息已经成为人们生活的重要组成部分,Lucene是构建搜索引擎的其中一种方式。搜索引擎系统是在.Net平台上用C#开发的,数据库是MSSQL Server 2000。主要完成的功能有:用爬虫抓取网页;获取有效信息放入数据库;通过Lucene建立索引;对简单关键字进行搜索;使用Ajax的局部刷新页面展示结果。
本文详细说明了系统开发的背景,开发环境,系统的需求分析,以及功能的设计与实现。同时讲述了搜索引擎的原理,系统功能,并探讨使用Ajax与服务器进行数据异步交互,从而改善现有的Web应用模式。
关键词:Lucene.net;异步更新;Ajax;搜索引擎
2.1 全文搜索引擎
2.1.1 搜索引擎的分类
全文搜索引擎通过从互联网上提取的各个网站的信息(以网页文字为主)而建立的数据库中,检索与用户查询条件匹配的相关记录,然后按一定的排列顺序将结果返回给用户。从搜索来源的角度,全文搜索引擎又可细分为两种,一种是拥有自己的检索程序(Indexer),俗称“蜘蛛”(Spider)程序或“机器人”(Robot)程序,并自建网页数据库,搜索结果直接从自身的数据库中调用;另一种则是租用其他引擎的数据库,并按自定的格式排列搜索结果。
分类目录则是通过人工的方式收集整理网站资料形成数据库的,比如雅虎中国以及国内的搜狐、新浪、网易分类目录。另外,在网上的一些导航站点,也可以归属为原始的分类目录。
2.1.2 搜索引擎的工作原理
搜索引擎的原理,可以看作三步:从互联网上抓取网页,建立索引数据库,在索引数据库中搜索。
利用能够从互联网上自动收集网页的Spider程序,自动访问互联网,并沿着网页中的所有URL爬到其它网页,重复这过程,并把爬过的所有网页收集回来。然后建立索引数据库,由分析索引程序对收集回来的网页进行分析,提取相关网页信息(包括网页所在URL、编码类型、页面内容包含的关键词、关键词位置、生成时间、大小、与其它网页的链接关系等),然后用这些相关信息建立网页索引数据库。接下来在索引数据库中搜索排序,当用户输入关键词搜索后,由搜索系统程序从网页索引数据库中找到符合该关键词的所有相关网页。最后,由页面生成系统将搜索结果的链接地址和页面内容摘要等内容组织起来返回给用户。搜索引擎只能搜到它网页索引数据库里储存的内容。
2.2 Lucene与搜索引擎
Lucene是一个全文信息检索工具包,为应用程序提供索引和搜索功能。和Java Lucene兼容的Lucene.net可以用在.net平台。Lucene能够为文本类型的数据建立索引,所以你只要能把你要索引的数据格式转化的文本的,Lucene就能对你的文档进行索引和搜索。比如你要对一些HTML文档,PDF文档进行索引的话你就首先需要把HTML文档和PDF文档转化成文本格式的,然后将转化后的内容交给Lucene进行索引,然后把创建好的索引文件保存到磁盘或者内存中,最后根据用户输入的查询条件在索引文件上进行查询。不规定要索引的文档的格式也使Lucene能够适用于几乎所有的搜索应用程序。
2.3 索引和搜索
索引是现代搜索引擎的核心,建立索引是把数据源处理成非常方便查询的索引文件的过程。为什么索引这么重要呢,试想你现在要在大量的文档中搜索含有某个关键词的文档,那么如果不建立索引的话你就需要把这些文档顺序的读入内存,然后检查这个文章中是不是含有要查找的关键词,这样的话就会耗费非常多的时间,想想搜索引擎可是在毫秒级的时间内查找出要搜索的结果的。这就是由于建立了索引的原因,你可以把索引想象成这样一种数据结构,他能够使你快速的随机访问存储在索引中的关键词,进而找到该关键词所关联的文档。Lucene采用的是一种称为反向索引(inverted index)的机制。反向索引就是说我们维护了一个词/短语表,对于这个表中的每个词/短语,都有一个链表描述了有哪些文档包含了这个词/短语。这样在用户输入查询条件的时候,就能非常快的得到搜索结果。我们将在本系列文章的第二部分详细介绍Lucene的索引机制,由于Lucene提供了简单易用的API,所以也可以非常容易的使用Lucene对文档实现索引的建立。
2.4 Ajax技术
Ajax全称为“Asynchronous JavaScript and XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。Ajax技术是目前在浏览器中通过JavaScript脚本可以使用的所有技术的集合。包括:HTML和CSS,使用文档对象模型DOM作动态显示和交互,使用XML做数据交互和操作,使用XMLHttpRequest进行异步数据接收,使用JavaScript将它们绑定在一起。
Ajax技术之中,核心的技术就是XMLHttpRequest,它最初的名称叫做XMLHTTP,是微软公司为了满足开发者的需要,1999年在IE5.0浏览器中率先推出的。后来这个技术被上述的规范命名为XMLHttpRequest。它正是Ajax技术之所以与众不同的地方。简而言之,XMLHttpRequest为运行于浏览器中的JavaScript脚本提供了一种在页面之内与服务器通信的手段。页面内的JavaScript可以在不刷新页面的情况下从服务器获取数据,或者向服务器提交数据。XMLHttpRequest的出现为Web开发提供了一种全新的可能性,甚至整个改变了人们对于Web应用由什么来组成的看法。
5.1 开发环境
开发平台的选择:本系统的开发平台选择微软公司的.NET,开发工具采用ASP.NET。.NET是Microsoft面向Web服务的平台,由框架、Web服务、.NET企业服务器等几部分组成,提供涉及面较广、功能较全面的解决方案。数据库选择:根据需求分析选择了MSSQL Server 2000。
5.2 关键代码详解
5.2.1 代码结构
如图6:
在网页爬虫Console端应用程序里输入一个有效的URL后这部份就开始从第一个URL开始遍历相关的链接并把相关的信息写入到网页数据存储数据库里,然后就由索引生成程序读取网页数据存储数据库,对每条记录生成索引记录,存放于生成的索引库文件里。生成索引需要调用Lucene.Net类。索引生成后在查询部分就能够在网页上输入关键字,对刚才抓取的信息的查询。并可以定位到信息的出处。下面对各部分关键代码进行详解。
5.2.2 爬虫部分
这部份的功能就是从输入的URL开始遍历各个相关的网页,它包括三个功能模块:网页抓取模块、网页减肥模块、爬虫维持模块。
首先定义一些变量用于保存抓取到的网页信息,urlList用于保存当前页面上的URL集合。然后根据全局变量url抓取此URL的网页信息到字节流变量里,经过转码后读取到变量PageString里,下步通过函数GetHttpUrl(PageString)对PageString中的URL标记进行提取并返回到urlList变量里,函数GetTitle(PageString)、parseScript(PageString)、parseHtml(PageString)、parseChar(Content)分别对网页信息变量获取标题、去除脚本块、去除HTML标记、去除特殊字符操作。再下步就是对获取到的标题、网页内容、链接等信息调用数据库操作通用类DAI保存到数据库里,这就实现了一个网页的抓取。再下步就是循环的对获取到的URL列表创建线程,针对每个URL来循环的执行上面的网页信息的抓取操作。具体代码如下:
private static void UrlThread()
{
String title="";
String Content="";
String mata="";
string URL="";
string[] urlArr = null;
StringBuilder urlList = new StringBuilder();
System.Net.WebClient Client=new System.Net.WebClient();
try
{
Stream strm=null;
try
{//读取一个URL的信息到流变量里
Stream strm=Client.OpenRead(url);
}
catch
{
console.WriteLine("url无法找到!");
return;
}
StreamReader sr=new StreamReader(strm,Encoding.GetEncoding("gb2312"));
String PageString=sr.ReadToEnd();//从流中读取网页信息到字符串变量中
strm.Close();
urlList = GetHttpUrl(PageString);
title=GetTitle(PageString);
Content = parseScript(PageString); //去掉脚本的网页文本
Content=parseHtml(PageString); //得到去了HTML标签的网页文本
URL=url;
mata="";
Content = parseChar(Content);
if((title != "" || title != string.Empty) && URL != "")
{
DAI.RunSqlNonQuery("insert into WebContent(url,content,title,mata) values('"+URL+"','"+Content+"','"+title+"','"+mata+"')");
Console.WriteLine("对url:"+URL+"相关信息写入数据库成功!");
}
else
{
Console.WriteLine("对url:"+URL+"相关信息写入数据库失败!");
}
urlArr=urlList.ToString().Split('|');
//对前面获取的URL列表循环的创建线程再执行本方法实现爬虫的维持
for(int i=0;i<urlArr.Length;i++)
{
url=urlArr[i];
if(url == "" || url == null || url == string.Empty)
continue;
Thread th = new Thread(new ThreadStart(UrlThread));
th.Start();
}
}
catch{}
}
5.2.3索引生成
这部分包含对文本的索引生成以及对数据库数据的索引生成,下面只对数据库索引生成的关键代码进行介绍:
下面这段代码实现对数据库里存储的记录创建索引。主要通过Lucene提供的方法来协助实现。
public Indexer(string indexDir)
{
#region Lucene Code
首先通过标准分词定义了一个索引写入器
IndexWriter writer = new IndexWriter(indexDir, new StandardAnalyzer(), true);
在创建索引库时,会合并多个Segments文件。此方式有助于减少索引文件数量,减少同时打开的文件数量。
writer.SetUseCompoundFile(false);
//删除以前生成的索引文件。
System.IO.Directory.Delete(iDexDir,true);
#endregion
DateTime start = DateTime.Now;
DoIndexByDB(writer);//
DateTime end = DateTime.Now;
int docNum = writer.DocCount();
Console.WriteLine("Index Finished. {0} Documents takes {1} second.",
docNum, ((TimeSpan)(end - start)).TotalSeconds);
writer.Optimize();
writer.Close();
}
使用Lucene提供的方法对数据库中的每条记录建立索引实现如下:
Document doc = new Document();
Console.WriteLine("Indexing {0} ", row["title"].ToString());
doc.Add(Field.Text("contents", row["content"].ToString()));
doc.Add(Field.Keyword("title", row["title"].ToString()));
doc.Add(Field.Keyword("mata",row["mata"].ToString()));
doc.Add(Field.Keyword("CreateDate",row["CreateDate"].ToString()));
doc.Add(Field.Keyword("Url",row["Url"].ToString()));
doc.Add(Field.Keyword("ID",row["ID"].ToString()));
writer.AddDocument(doc);
5.2.4页面查询
这部分主要完成的功能是获取前台表单中输入的关键字,在程序中获取查询结果,最后把列表显示在前台页面。
Ajax在此部分中被使用到,它完成的功能是部分刷新页面,不需整个页面的重新加载。为了方便的在程序中使用Ajax,此系统引用了封装完善的Ajax类库。在程序中注册后,在html里就可以使用Javascript来调用后台的程序。选取部分代码来说明:
首先在页面后台程序中进行Ajax注册,代码如下:
private void Page_Load(object sender, System.EventArgs e)
{
//ajax注册
AjaxPro.Utility.RegisterTypeForAjax(typeof(Search));
}
如果前台Javascript需要调用某个方法,那就在那个函数前加上[AjaxPro.AjaxMethod],表示此方法属于ajax应用。
[AjaxPro.AjaxMethod]
public string SearchResult(string keywords,string pageNo)
{
其中,前台所存在的文字的代码如下:
StringBuilder sb = new StringBuilder();
sb.Append("<tr><td>结果数:"+result+" 所用时间:"+t+"毫秒</td></tr>");
前台显示结果记录的代码,动态生成table标签,如下:
for(int i = startNum ; i < endNum; i++)
{
在显示内容中,仍然使用到了Lucene提供的类,可以方便的从所建立的索引文档中获取网址,网页标题,内容,时间。
Document doc = hits.Doc(i);
content=doc.Get("contents");
content=content.Replace(keywords,"<font color=red>"+keywords+"</font>");
sb.Append("<tr class="+c+">");
sb.Append("<td><a href="+doc.Get("Url")+">"+doc.Get("title")+"</a></td>");
sb.Append("</tr>");
sb.Append("<tr class="+c+">");
sb.Append("<td>"+content+"<br>"+doc.Get("CreateDate")+"</td>");
sb.Append("</tr>");
}
}
结 论
本课题主要探讨了搜索引擎的原理,介绍了原理和过程,并给出了使用Lucene与Ajax实现的方法。该系统引入了当前用于构建搜索引擎的Lucene工具包,在.Net环境下,充分利用Lucene所提供的工具,完成搜索引擎的基本功能。