您的位置:首页 > 其它

Lucene.net

2016-05-14 23:14 417 查看
http://www.cnblogs.com/piziyimao/archive/2013/01/31/2887072.html

一、站内搜索

like模糊程度太低,无法匹配几个关键词不挨着的,造成全表扫描,效率低。

数据库自身的全文检索功能很傻瓜,和普通SQL一样,灵活性不强。

二、Lucene.net 简介

Lucene.net只是一个全文检索开发包(就像ADO.NET和管理系统的关系),不是一个成型的搜索引擎,它的功能就是:把数据扔给Lucene.net,查询数据的时候从Lucene.net查询数据,可以看做是提供了全文检索功能的一个数据库。只能对文本信息进行检索,如果不是文本信息,要转换为文本信息,比如要检索Excel文件,就要用NPOI把excel读取成字符串,然后把数据扔给Lucene.net,Lucene.net会吧扔给它的文本切词保存,加快检索速度。

三、分词

    分词是核心的算法,搜索引擎内部保存的就是一个个的词,英文分词很简单,按照空格分隔就可以,中文分词则麻烦。“the”,",","和",“啊”,“的”等对于搜索引擎来说无意义的词一般都属于不参与分词的无意义单词。

    Lucene.net中不同的分词算法就是不同的类,所有分词算法类都从Analyzer继承,不同的分词算法有不同的优缺点。

1.一元分词算法:Lucene.net内置的StandardAnalyzer,将英文单词按空格、标点符号等进行分词,将中文按照单个字进行分词,一个汉字算一个词。

(引用Lucene.net.dll)

protected void Button1_Click(object sender, EventArgs e)
{
Analyzer analyzer = new StandardAnalyzer();
TokenStream tokenStream = analyzer.TokenStream("",new StringReader(TextBox1.Text));
Token token = null;
ListBox1.Items.Clear();
while ((token = tokenStream.Next()) != null)
{
string word = token.TermText();
ListBox1.Items.Add(word);
}

}
2.二元分词算法:CJKAnalyzer类,没两个字算一个词。

无论是一元分词还是二元分词,分词效率比较高,但是分出无用词,因此索引库大。

3.基于词库的分词算法:基于一个词库进行分词,可以提高分词的成功率,有庖丁解牛,盘古分词等,效率低,但精准。

盘古分词:(引用PanGu.dll, PanGu.Lucene.Analyzer.dll),在项目中新建词库文件夹“Dict”,将词库文件放到里面,对每个文件-属性-复制到输出目录-选择“如果较新则复制”。

protected void Button1_Click(object sender, EventArgs e)
{
// Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new PanGuAnalyzer();
TokenStream tokenStream = analyzer.TokenStream("",new StringReader(TextBox1.Text));
Token token = null;
ListBox1.Items.Clear();
while ((token = tokenStream.Next()) != null)
{
string word = token.TermText();
ListBox1.Items.Add(word);
}

}
词库的增删改查:使用DictManage.exe 或 用用WordDictionary类从一个几千个行业单词的文本文件中批量导入词汇到pangu分词词库中。

四、Lucene.net核心类简介:

一)创建索引:

1.Directory类表示索引文件保存的地方(索引文件是Lucene.net用来保存用户扔过来的数据的地方),是个抽象类,两个子类:FSDirectory(文件中)、RAMDirectory(内存中)。

2.创建FSDirectory的方法:FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath),new NativeFSLockFactory()),indexPath表示索引的文件夹路径(应先在磁盘中创建该文件夹)

3.IndexReader类:对索引进行读取的类。 IndexWriter类:对索引进行写的类。

4.IndexReader的静态方法bool IndexExists(Directory directory) 判断目录是否是一个索引目录。

5.IndexWriter 的静态方法bool IsLocked(Directory directory) 判断目录是否锁定,在对目录写之前会先把目录锁定,两个IndexWriter 不能同时写一个索引文件,IndexWriter 在进行写操作的时候会自动加锁,close的时候会自动解锁。IndexWriter.Unlock方法手动解锁(比如还没来得及Close IndexWriter程序就崩溃了,可能造成一直被锁定)

protected void Button2_Click(object sender, EventArgs e)
{
string indexPath = @"F:\index";//注意和磁盘上文件夹的大小写一致,否则会报错。(先新建索引文件夹index)
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());
bool isUpdate = IndexReader.IndexExists(directory);
if (isUpdate)
{
//如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁
//Lucene.Net在写索引库之前会自动加锁,在close的时候会自动解锁
//不能多线程执行,只能处理意外被永远锁定的情况
if (IndexWriter.IsLocked(directory))
{
IndexWriter.Unlock(directory);
}
}
IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
for (int i = 1000; i < 1100; i++)
{
string txt = File.ReadAllText(@"F:\books\" + i + ".txt");
Document document = new Document();//一条Document相当于一条记录
document.Add(new Field("number", i.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//每个Document可以有自己的属性(字段),所有字段名都是自定义的,值都是string类型
document.Add(new Field("body", txt, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
writer.AddDocument(document);
Console.WriteLine("索引" + i + "完毕");
}
writer.Close();
directory.Close();//不要忘了Close,否则索引结果搜不到
}
二)根据索引进行搜索:

protected void Button1_Click(object sender, EventArgs e)
{
string indexPath = @"F:\index";
string kw = TextBox1.Text;
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
IndexReader reader = IndexReader.Open(directory, true);
IndexSearcher searcher = new IndexSearcher(reader);
PhraseQuery query = new PhraseQuery();
foreach (string word in kw.Split(' '))//先用空格,让用户去分词,空格分隔的就是词“计算机   专业”
{
query.Add(new Term("body", word));
}
query.SetSlop(100);
TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
searcher.Search(query, null, collector);
ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;
List<SearchResult> result = new List<SearchResult>();
for (int i = 0; i < docs.Length; i++)
{
int docId = docs[i].doc;
Document doc = searcher.Doc(docId);
string number = doc.Get("number");
string body = doc.Get("body");
SearchResult se = new SearchResult();
se.Number = number;
se.Body = body;
result.Add(se);
}
Repeater1.DataSource = result;
Repeater1.DataBind();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: