lucene.net学习

最近在了解关于页面站内搜索相关功能,如今大多数网站都有相关功能。

搜索可以通过以下四种办法来实现:

1.使用数据库的模糊查询:like '%视频教程%'。

2.使用数据库的全文检索功能。

3.使用百度、google的站内搜索

4.就是今天我要写的基于java版本Lucene移植过来的lucene.net来实现搜索。

问什么不使用前面三种方法来实现搜索啦?

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

        方法二   数据库全文检索很傻瓜化,和普通SQL一样。数据全文检索灵活性不强。

        方法三   受制于人;索引不及时、不全面、不精准;用户体验感差

 

Lucene.Net只是一个全文检索开发包,不是一个成型的搜索引擎,它的功能就是:把数据扔给Lucene.Net ,查询数据的时候从Lucene.Net 查询数据,可以看做是提供了全文检索功能的一个数据库。Lucene.Net不管文本数据怎么来的。用户可以基于Lucene.Net开发满足自己需求的搜索引擎。 Lucene.Net只能对文本信息进行检索。如果不是文本信息,要转换为文本信息,比如要检索Excel文件,就要用NPOI把Excel读取成字符串,然后把字符串扔给Lucene.Net。Lucene.Net会把扔给它的文本切词保存,加快检索速度。midomi.com。因为是保存的时候分词(切词),所以搜索速度非常快!

 

 

lucene分词是核心的算法,搜索引擎内部保存的就是一个个的“词(Word)”。Lucene.net中不同的分词算法就是不同的类,而所有的分词算法类都从Analyzer类继承。

首先在项目的根路径下加入Lucene.Net.dll和Lucene.Net.pdb的引用。

 

第一种:内置的StandardAnalyzer 是将英文按照空格、标点符号等进行分词,将中文按照单个字进行分词,一个汉字算一个词。

 1 //实例化一个StandardAnalyzer类的对象
 2 Analyzer analyzer = new StandardAnalyzer();
 3 //通过分析器得到一个TokenStream
 4 TokenStream tokenStream = analyzer.TokenStream("",new StringReader("北京,Hi欢迎你们大家"));
 5 Lucene.Net.Analysis.Token token = null;
 6 //通过循环,Next()继续分词,如果没有更多词,则返回null
 7 while ((token = tokenStream.Next()) != null)
 8 {
 9 //输出分词后的结果
10      Console.WriteLine(token.TermText());
11 }
View Code

 

 

第二种:二元分词算法,每两个汉字算一个单词,“北京欢迎你”会分词为“北京  京欢   欢迎  迎你”。

这里介绍的CJKAnalyzer二元分词,和上面的StandardAnalyzer 代码相似,这里代码就不写了。只需要把实例化类改为CJKAnalyzer类就行了。

 

第三种:基于词库的分词算法,基于一个词库进行分词,可以提高分词的成功率。有庖丁解牛、盘古分词等。

这里介绍盘古分词

PanGu4Lucene下载地址我放到百度云盘里,需要的请自行下载http://pan.baidu.com/s/1GGBgr

打开PanGu4Lucene\WebDemo\Bin,将Dictionaries添加到项目的根路径下(并改名为Dict),

添加对PanGu.dllPanGu.Lucene.Analyzer.dll的引用。当然这里也需要添加对Lucene.Net.dll和Lucene.Net.pdb的引用。这里需要注意:同目录下不要有Pangu.xml
盘古分词只对常用的进行分词,如果想自行添加分词,可以使用盘古分词自带的管理工具进行添加。当用户添加分词词组后,如果不更新到项目中依然是无法根据用户添加的来进行分词的。程序运行的时候会到项目根目录的Debug\Dict文件夹下寻找分词特征文件,所以需要设置项目根目录下的dict文件夹下文件的属性,这样只要特征文件改变,就会在编译时自动更新到项目根目录的Debug\Dict文件夹下。
 
 

 先测试一下盘古分词:

建立一个winform项目

      

测试代码:

 

 1 private void button1_Click(object sender, EventArgs e)
 2         {
 3             listBox1.Items.Clear();
 4             //需要分词的字符串
 5             string s = "程序员的生活,请注意自己的身体,少熬夜!!身体才是本钱。";
 6            //实例化一个PanGuAnalyzer类的实例
 7             Analyzer analyzer = new PanGuAnalyzer();
 8 
 9             TokenStream tokenStream = analyzer.TokenStream("", new StringReader(s));
10 
11             Lucene.Net.Analysis.Token token = null;
12             while ((token = tokenStream.Next()) != null)//Next继续分词,如果没有更多词,则返回null
13             {
14                 listBox1.Items.Add(token.TermText());//得到分到的词
15             }
16         }
View Code

 

 

下面来完成实际场景实例:

 

首先也建立一个winform项目,也可以在上面项目中直接添加也行。当然这里也可以使用webform来实现,这里就不详解了。

首先我们要先创建索引:

 1 string indexPath = @"C:\LucenePanGudir";//注意和磁盘上文件夹的大小写一致,否则会报错。
 2 FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath),new NativeFSLockFactory());//根据文件夹建立一个FSDirectory 
 3 bool isUpdate = IndexReader.IndexExists(directory);//索引库文件夹存在并且存在索引库特征文件
 4             if (isUpdate)
 5             {
 6                 //同时只能有一段代码对索引库进行写操作!当使用IndexWriter打开directory的时候会自动给索引库上锁。!!!
 7                 //先判断索引目录是否被锁定。如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁
 8             if (IndexWriter.IsLocked(directory))
 9                 {
10                   IndexWriter.Unlock(directory);
11                 }
12             }
13  IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
14             for (int i = 1; i < 100; i++)
15             {
16                 string txt = File.ReadAllText(@"D:\lucene\PanGuTestArticle\" + i + ".txt");//用于建立索引需要的文章,这里可以通过读取数据库来获得建立索引的数据源,这里就不详解了。
17                 Document document = new Document();//用于存储需要建立索引的一篇文档
18                 
19                 //Field.Store表示是否保存字段原值。Field.Store.YES的字段才能用document.Get取出来值
20                //字段的值是字符串类型-- i.ToString()
21                 document.Add(new Field("number", i.ToString(), Field.Store.YES, Field.Index. NOT_ANALYZED));
22                 //要进行全文检索的字段要设置 Field.Index. ANALYZED
23                 document.Add(new Field("body", txt, Field.Store.YES, Field.Index. ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
24                 writer.AddDocument(document);//文档写入索引库
25             }
26             writer.Close();
27             directory.Close();//不要忘了Close,否则索引结果搜不到
View Code

 

 下面就可以通过代码来实现搜索的功能

 1 string indexPath = @"C:\LucenePanGudir";
 2 
 3             FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
 4             IndexReader reader = IndexReader.Open(directory, true);
 5             IndexSearcher searcher = new IndexSearcher(reader);//创建一个索引搜索器。
 6             
 7             //搜索条件
 8             PhraseQuery query = new PhraseQuery();
 9             //添加搜索条件,这里也可以先得到用户输入的搜索条件使用盘古分词法来得到要添加的搜索条件。方法和上面我写的盘古分词测试代码相似,这里就不再详解了。
10             query.Add(new Term("body", "程序"));//body中含有程序的文章
11             query.Add(new Term("body", "大学生"));//Add的查询条件是and的关系, 相当于sql语句的where Contains("body","程序") and Contains("body","大学生")
12             query.SetSlop(100);//多个查询条件的词之间的最大距离。在文章中相隔太远一般也就无意义
13             //TopScoreDocCollector是盛放查询结果的容器
14             TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
15             searcher.Search(query, null, collector);//根据query查询条件进行查询,查询结果放入collector容器
16             ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;//得到所有查询结果中的文档。TopDocs可以实现分页
17             for (int i = 0; i < docs.Length; i++)
18             {
19                 //搜索ScoreDoc[]只能获得文档的id,这样不会把查询结果的Document一次性加载到内存中。降低了内存压力
20                 //需要获得文档的详细内容的时候通过searcher.Doc来根据文档id来获得文档的详细内容对象Document
21                 int docId = docs[i].doc;//得到查询结果文档的id(Lucene内部分配的id)
22                 Document doc = searcher.Doc(docId);//找到文档id对应的文档详细信息
23                 textBox1.AppendText(doc.Get("number")+"\n");//取出放进去字段的值
24                 textBox1.AppendText(doc.Get("body") + "\n");//Field.Store.YE的字段才能用document.Get取出来值
25                 textBox1.AppendText("-----------------------\n");
26             }
View Code

 

以上是本人对lucene.net学习,如有什么缺陷,望大牛们多多提出意见,本人不胜感激!!!

posted on 2013-10-17 12:30  TomHom  阅读(501)  评论(0编辑  收藏  举报