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版本与之有很大出入,之所以不用最新版,是为了配合盘古分词。

  首先给出一些入门的资源:

  1. How to get started with Lucene.Net
  2. The Main Concepts
  3. Your First Application
  4. Dissecting Storage Documents and Fields
  5. Lucene - or how I stopped worrying and learned to love unstructured data
  6. How Subtext Lucene.Net index is structured

   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();

 

 

 

posted @ 2012-11-26 00:14  MagicCode1023  阅读(441)  评论(0编辑  收藏  举报