Beta笔记——搜索引擎的设计与实现(1):使用Lucene.Net建立索引与中文分词
回寝室前花几分钟的时间写一下我目前对学霸搜索引擎的构建工具:Lucene.Net与盘古分词的使用.
1. 简介
Lucene.Net是优秀的Java平台下的开源搜索引擎解决方案Lucene的.Net版本,在学霸项目中,我们使用的是2.9.2版本。
盘古分词是开源的中文分词软件,分词速度快,支持自定义词典与停词设置,能够与Lucene.Net做到无缝整合,学霸中使用的是最新的2.3.3版本。
2. Lucene.Net HelloWorld
在测试过程中,我尝试了Lucene的多个不同版本,让我不能理解的是,不同版本的Lucene的各个操作语法出入很大,而且不同版本的索引不能够共享。下面以2.9.2版本为例,最新3.0.3版本与之有很大出入,之所以不用最新版,是为了配合盘古分词。
首先给出一些入门的资源:
2.1 建立索引目录
在向Lucene.Net灌入数据之前,首先需要设置索引的存放路径,Lucene.Net支持磁盘索引与内存索引,这里以磁盘索引为例:
Directory directory = FSDirectory.GetDirectory("LuceneIndex");
2.2 建立分析器
分析器用来对数据进行分词,便于后续建立倒排索引。
Analyzer analyzer = new StandardAnalyzer();
2.3 建立IndexWriter
IndexWriter用来将Document写入索引文件,并建立好倒排索引
IndexWriter writer = new IndexWriter(directory, analyzer);
//添加索引的方法 addDocs(writer);
writer.Optimize(); writer.Commit(); writer.Close();
其中addDocs(writer)的方法代码为:
List<Question> qlist = new QuestionManager().GetQuestions(1); foreach (Question q in qlist) { Lucene.Net.Documents.Document doc = new Lucene.Net.Documents.Document(); doc.Add(new Field("qid", q.Id.ToString(), Field.Store.YES, Field.Index.NO)); // doc.Add(new Field("tags",q.Tags)) doc.Add(new Field("title", q.Title, Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field("content", q.Content, Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field("created", q.PostDateTime.ToShortDateString(), Field.Store.NO, Field.Index.NOT_ANALYZED)); doc.Add(new Field("repiles", q.Replies.ToString(), Field.Store.NO, Field.Index.NOT_ANALYZED)); doc.Add(new Field("views", q.Views.ToString(), Field.Store.NO, Field.Index.NOT_ANALYZED)); writer.AddDocument(doc); }
2.4 搜索
索引建立好啦,下面开始搜索,首先初始化Searcher,使用QueryParser对QueryString进行分析处理,然后提交Searcher对象,返回的结果保存在Hits中
IndexSearcher searcher = new IndexSearcher(directory,false); QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "title", new PanGuAnalyzer(true)); //Supply conditions string keys = "flash C++"; keys = GetKeyWordsSplitBySpace(keys, new PanGuTokenizer()); Query query = parser.Parse(keys); //Do the search Hits hits = searcher.Search(query); ScoreDoc[] result = searcher.Search(query, null, 100).scoreDocs; for (int i = 0; i < result.Length; i++) Console.WriteLine(searcher.Doc(result[i].doc).Get("title"));
最后不要忘记关闭资源
analyzer.Close();
writer.Close();
directory.Close();
3. 整合盘古分词
在测试时,我发现使用官方编译的版本整合进Lucene.Net中,无法得到搜索结果,官方blog中对问题进行了说明(http://www.cnblogs.com/eaglet/archive/2010/05/12/1733581.html#2529278),但是,我发现使用官方编译版本依旧无法得到搜索结果,无奈只能下载源码自行编译最新的2.3.3版本。
整合过程比较简单,将StandardAnalyzer替换为PanGuAnalyzer即可。
PanGu.Segment.Init(); Directory directory = FSDirectory.GetDirectory("LuceneIndex"); //Analyzer analyzer = new StandardAnalyzer(); Analyzer analyzer =new PanGuAnalyzer(); IndexWriter writer = new IndexWriter(directory, analyzer); //addDocs(writer); writer.Optimize(); writer.Commit(); writer.Close(); IndexSearcher searcher = new IndexSearcher(directory,false); //QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29,"title", analyzer); QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "title", new PanGuAnalyzer(true)); //Supply conditions string keys = "flash C++"; keys = GetKeyWordsSplitBySpace(keys, new PanGuTokenizer()); Query query = parser.Parse(keys); //Do the search Hits hits = searcher.Search(query); ScoreDoc[] result = searcher.Search(query, null, 100).scoreDocs; for (int i = 0; i < result.Length; i++) Console.WriteLine(searcher.Doc(result[i].doc).Get("title")); analyzer.Close(); writer.Close(); directory.Close();