DotLucene搜索引擎Demo之:创建索引
99收藏夹(注1)里面有个在线帮助,他是用StreamReader来读文本数据的,其他的是读数据库,我发现不管是读数据库还是一xml的形式读xml文档,不管你的数据库如何优化,也不管你的机器培植如何之高,读的速度与读文本数据的速度是不可比的,大家也可到http://www.99scj.com/测试下。点在线帮助,一闪就出来了。
本文是按照DotLucene官方网站的一个demo 写的,本同点在于,
1,本文的demo采用了DotLucene最新稳定版1.4.3
2,开发环境是vs2005。
3,demo被我划成了两个部分,一个部分是一个console程序,就是本文所讲的,主要就是怎么样创建索引,另
一个部分是个web程序,关键说的是搜索这个部分所建立的索引。
4,源代码将在下个部分提供下载,因为这两个部分同属一个解决方案。
好了,我们现在开始进入怎么用DotLucene来创建索引了。
什么是索引呢?我也不太明白,我是这样理解的,索引就是用来加快查询数据的速度的,比如我们小时候读书的时候课本前面有那个第一课:什么什么的。。。。。。第几页,这应该就是索引吧。用DotLucene创建索引也就是说把某些文件内容编入某个目录下的索引。
首先运行vs2005,选择文件--新建项目,在弹出的对话框选:其他项目类型里的Visual Studio解决方案,选右边的空白解决方案,输入名字:SearchDemo,位置选D:\确定。
再在解决方案SearchDemo右键选添加---再选---新建解决方案文件夹,输入文件夹名字为Indexer.我再找到d:\SearchDemo,再这个文件夹里面新建个目录,叫wwwroot,大家就知道这个目录是放weB 程序的,我们在iis管理器里面新建设个虚拟目录,指向d:\SearchDemo\wwwroot目录,名字叫SearchDemo.
我们再在vs的解决方案SearchDemo单季右键选添加--新建解决方案文件夹,输入文件夹名字为web,其实这两个文件夹名都是vs虚拟的,其实并不存在。我们然后在第一个项目Indexer上右键选:添加==新建项目,再弹出的面板左边选v c#--windows--右边选控制台应用程序,输入名字Indexer,确定,这个时候vs会在d:\searchdemo目录下添加个Indexer目录,然后我们再在新添加的名为web项目上右建--添加---现有网站---选择我们刚刚建立的SearchDemo就是。
现在我们建设好了两个项目,一个console控制台项目和一个SearchDemo的web项目,我们这部分只讲第一个项目怎么样建立索引,要建立索引,我们首先必须明白索引应该建立在什么地方?为了方便我把索引建立在D:\SearchDemo\wwwroot目录下新建一个index目录下;还有我们必须明白哪些文件将被编入索引?也为了方便,我把要被编入索引的文件放在d:\SearchDemo\wwwroot目录下新建个documents目录下,也就是说documents目录下的所有文件都将被我编入索引。因为我们这个demo 演示的是搜索DotLucene的帮助文档,文艺我们把所有下载来的帮助文档文件全部拷入d:\SearchDemo\wwwroot\documents目录下。同时我们还必须赋予index目录写的权利。
我们现在给Indexer控制台项目添加引用Lucene.Net.dll
我们现在在Indexer控制台项目里添加个类:IntrnetIndexer.cs;
先说明下doc.Add(Field.UnStored("text", ParseHtml(html)));
doc.Add(Field.Keyword("path", relativePath));
doc.Add(Field.Text("title", GetTitle(html)));
索引是由Docuemnt对象组成,而Docuemnt对象又是由字段对象组成.
Field.UnStored方法在其官方网站上的说明是:Constructs a String-valued Field that is tokenized and indexed, but that is not stored in the index. Term vector will not be stored for this Field.搜价110的Eunge帮忙翻译下成这样:构造一个String类型的字段,它将被分词和索引,但是它不会被存储在索引中。关于这个字段的词向量不会被存储,我一直都未能够理解关于这个字段的词向量不会被存储的含义,汗。
代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
namespace Indexer
{
public class IntranetIndexer
{
//索引写入器
private IndexWriter writer;
//要写入索引的文件的根目录
private string docRootDirectory;
//要匹配的文件格式
private string pattern;
/// <summary>
/// 初始化一个索引写入器writer,directory为创建索引的目录,true代表如果不存在索引文件将重新创建索引文件,如果已经存在索引文件将覆写索引文件,如果为true将代表打开已经存在的索引文件
/// </summary>
/// <param name="directory">传入的要创建索引的目录,注意是字符串值,如果目录不存在,他将会被自动创建</param>
public IntranetIndexer(string directory)
{
writer = new IndexWriter(directory,new StandardAnalyzer(),true);
writer.SetUseCompoundFile(true);
}
public void AddDirection(DirectoryInfo directory,string pattern)
{
this.pattern = pattern;
this.docRootDirectory = directory.FullName;
AddSubDirectory(directory);
}
private void AddSubDirectory(DirectoryInfo directory)
{
foreach (FileInfo fi in directory.GetFiles(pattern))
{
//遍历要写入索引的目录的所有文件,把他先加入Docuemnt对象,再加入索引,因为索引都是有Document对象组成
AddHtmlToDocument(fi.FullName);
}
foreach (DirectoryInfo di in directory.GetDirectories())
{
//层层遍历递归,只到把所有的子目录子文件都搞完
AddSubDirectory(di);
}
}
private void AddHtmlToDocument(string path)
{
Document doc = new Document();
string html;
using (StreamReader sr = new StreamReader(path, System.Text.Encoding.Default))
{
html = sr.ReadToEnd();
}
int relativePathStartsAt = this.docRootDirectory.EndsWith("\\") ? this.docRootDirectory.Length : this.docRootDirectory.Length + 1;
string relativePath = path.Substring(relativePathStartsAt);
doc.Add(Field.UnStored("text", ParseHtml(html)));
doc.Add(Field.Keyword("path", relativePath));
doc.Add(Field.Text("title", GetTitle(html)));
writer.AddDocument(doc);
}
/// <summary>
/// 把读取的文件中的所有的html标记去掉,把 替换成空格
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
private string ParseHtml(string html)
{
string temp = Regex.Replace(html, "<[^>]*>", "");
return temp.Replace(" "," ");
}
/// <summary>
/// 获得读取的html文挡的标题
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
private string GetTitle(string html)
{
Match m = Regex.Match(html,"<title>(.*)</title>");
if (m.Groups.Count == 2)
return m.Groups[1].Value;
return "此文挡标题未知";
}
public void Close()
{
writer.Optimize();
writer.Close();
}
}
}