你的位置:首页 > ASP.net教程

[ASP.net教程]使用Lucene.NET实现站内搜索


使用Lucene.NET实现站内搜索

  1. 导入Lucene.NET 开发包

    Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene.Net 是 .NET 版的Lucene。

    你可以在这里下载到最新的Lucene.NET

  2. 创建索引、更新索引、删除索引

  3. 搜索,根据索引查找

     1 using System; 2 using Lucene.Net.Store; 3 using Lucene.Net.Index; 4 using Lucene.Net.Analysis.PanGu; 5 using Lucene.Net.Documents; 6  7 namespace BLL 8 { 9   class IndexHelper 10   { 11     /// <summary> 12     /// 日志小助手 13     /// </summary> 14     static Common.LogHelper logger = new Common.LogHelper(typeof(SearchBLL)); 15     /// <summary> 16     /// 索引保存的位置,保存在配置文件中从配置文件读取 17     /// </summary> 18     static string indexPath = Common.ConfigurationHelper.AppSettingMapPath("IndexPath"); 19      20     /// <summary> 21     /// 创建索引文件或更新索引文件 22     /// </summary> 23     /// <param name="item">索引信息</param> 24     public static void CreateIndex(Model.HelperModel.IndexFileHelper item) 25     { 26       try 27       { 28         //索引存储库 29         FSDirectory directory = FSDirectory.Open(new System.IO.DirectoryInfo(indexPath), new NativeFSLockFactory()); 30         //判断索引是否存在 31         bool isUpdate = IndexReader.IndexExists(directory); 32         if (isUpdate) 33         { 34           //如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁 35           if (IndexWriter.IsLocked(directory)) 36           { 37             //解锁索引库 38             IndexWriter.Unlock(directory); 39           } 40         } 41         //创建IndexWriter对象,添加索引 42         IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED); 43         //获取新闻 title部分 44         string title = item.FileTitle; 45         //获取新闻主内容 46         string body = item.FileContent; 47         //为避免重复索引,所以先删除number=i的记录,再重新添加 48         //尤其是更新的话,更是必须要先删除之前的索引 49         writer.DeleteDocuments(new Term("id", item.FileName)); 50         //创建索引文件 Document 51         Document document = new Document(); 52         //只有对需要全文检索的字段才ANALYZED 53         //添加id字段 54         document.Add(new Field("id", item.FileName, Field.Store.YES, Field.Index.NOT_ANALYZED)); 55         //添加title字段 56         document.Add(new Field("title", title, Field.Store.YES, Field.Index.NOT_ANALYZED)); 57         //添加body字段 58         document.Add(new Field("body", body, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS)); 59         //添加url字段 60         document.Add(new Field("url", item.FilePath, Field.Store.YES, Field.Index.NOT_ANALYZED)); 61         //写入索引库 62         writer.AddDocument(document); 63         //关闭资源 64         writer.Close(); 65         //不要忘了Close,否则索引结果搜不到 66         directory.Close(); 67         //记录日志 68         logger.Debug(String.Format("索引{0}创建成功",item.FileName)); 69       } 70       catch (SystemException ex) 71       { 72         //记录错误日志 73         logger.Error(ex); 74         throw; 75       } 76       catch (Exception ex) 77       { 78         //记录错误日志 79         logger.Error(ex); 80         throw; 81       } 82     } 83  84     /// <summary> 85     /// 根据id删除相应索引 86     /// </summary> 87     /// <param name="guid">要删除的索引id</param> 88     public static void DeleteIndex(string guid) 89     { 90       try 91       { 92         ////索引存储库 93         FSDirectory directory = FSDirectory.Open(new System.IO.DirectoryInfo(indexPath), new NativeFSLockFactory()); 94         //判断索引库是否存在索引 95         bool isUpdate = IndexReader.IndexExists(directory); 96         if (isUpdate) 97         { 98           //如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁 99           if (IndexWriter.IsLocked(directory))100           {101             IndexWriter.Unlock(directory);102           }103         }104         IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);105         //删除索引文件106         writer.DeleteDocuments(new Term("id", guid));107         writer.Close();108         directory.Close();//不要忘了Close,否则索引结果搜不到109         logger.Debug(String.Format("删除索引{0}成功", guid));110       }111       catch (Exception ex)112       {113         //记录日志114         logger.Error(ex);115         //抛出异常116         throw;117       }118     }119   }120 }

    IndexHelper 添加、更新、删除索引
     1 using Lucene.Net.Analysis; 2 using Lucene.Net.Analysis.PanGu; 3 using Lucene.Net.Documents; 4 using Lucene.Net.Index; 5 using Lucene.Net.Search; 6 using Lucene.Net.Store; 7 using Model.HelperModel; 8 using System; 9 using System.Collections.Generic; 10  11 namespace BLL 12 { 13   public static class SearchBLL 14   { 15     //一个类中可能会有多处输出到日志,多处需要记录日志,常将logger做成static 静态变量 16     /// <summary> 17     /// 日志助手 18     /// </summary> 19     static Common.LogHelper logger = new Common.LogHelper(typeof(SearchBLL)); 20     /// <summary> 21     /// 索引保存位置 22     /// </summary> 23     static string indexPath = Common.ConfigurationHelper.AppSettingMapPath("IndexPath"); 24     /// <summary> 25     /// 搜索 26     /// </summary> 27     /// <param name="keywords">用户搜索的关键词</param> 28     /// <returns>返回搜索的结果</returns> 29     public static List<SearchResult> Search(string keywords) 30     { 31       try 32       { 33         //索引存储库 34         FSDirectory directory = FSDirectory.Open(new System.IO.DirectoryInfo(indexPath), new NoLockFactory()); 35         //创建IndexReader对象 36         IndexReader reader = IndexReader.Open(directory, true); 37         //创建IndexSearcher对象 38         IndexSearcher searcher = new IndexSearcher(reader); 39         //新建PhraseQuery 查询对象 40         PhraseQuery query = new PhraseQuery(); 41         //把用户输入的关键词进行拆词 42         foreach (string word in SplitWord(keywords)) 43         { 44           //添加搜索关键词 45           query.Add(new Term("body", word)); 46         } 47         //设置分词间距为100字之内 48         query.SetSlop(100); 49         TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true); 50         //根据查询条件查询结果 51         searcher.Search(query, null, collector); 52         //搜索到的ScoreDoc结果 53         ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs; 54         //保存搜索结果的list 55         List<SearchResult> listResult = new List<SearchResult>(); 56         for (int i = 0; i < docs.Length; i++) 57         { 58           //取到文档的编号(主键,这个是Lucene .net分配的) 59           //检索结果中只有文档的id,如果要取Document,则需要Doc再去取 60           //降低内容占用 61           int docId = docs[i].doc; 62           //根据id找Document 63           Document doc = searcher.Doc(docId); 64           string number = doc.Get("id"); 65           string title = doc.Get("title"); 66           string body = doc.Get("body"); 67           string url = doc.Get("url"); 68           //建立一个搜索结果对象 69           SearchResult result = new SearchResult(); 70           result.Number = number; 71           result.Title = title; 72           result.BodyPreview = Preview(body, keywords); 73           result.Url = url; 74           //添加到结果列表 75           listResult.Add(result); 76         } 77         if (listResult.Count == 0) 78         { 79           return null; 80         } 81         else 82         { 83           return listResult; 84         } 85       } 86       catch (SystemException ex) 87       { 88         logger.Error(ex); 89         return null; 90       } 91       catch (Exception ex) 92       { 93         logger.Error(ex); 94         return null; 95       } 96     } 97  98     /// <summary> 99     /// 获取内容预览100     /// </summary>101     /// <param name="body">内容</param>102     /// <param name="keyword">关键词</param>103     /// <returns></returns>104     private static string Preview(string body, string keyword)105     {106       //创建HTMLFormatter,参数为高亮单词的前后缀 107       PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");108       //创建 Highlighter ,输入HTMLFormatter 和 盘古分词对象Semgent 109       PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new PanGu.Segment());110       //设置每个摘要段的字符数 111       highlighter.FragmentSize = 100;112       //获取最匹配的摘要段 113       string bodyPreview = highlighter.GetBestFragment(keyword, body);114       return bodyPreview;115     }116 117     /// <summary>118     /// 盘古分词,对用户输入的搜索关键词进行分词119     /// </summary>120     /// <param name="str">用户输入的关键词</param>121     /// <returns>分词之后的结果组成的数组</returns>122     private static string[] SplitWord(string str)123     {124       List<string> list = new List<string>();125       Analyzer analyzer = new PanGuAnalyzer();126       TokenStream tokenStream = analyzer.TokenStream("", new System.IO.StringReader(str));127       Lucene.Net.Analysis.Token token = null;128       while ((token = tokenStream.Next()) != null)129       {130         list.Add(token.TermText());131       }132       return list.ToArray();133     }134   }135 }

    Search 通过查找索引实现搜索
     1 namespace Model.HelperModel 2 { 3   public class SearchResult 4   { 5     public string Number { get; set; } 6  7     public string Title { get; set; } 8  9     public string BodyPreview { get; set; }10 11     public string Url { get; set; }12   }13 }

    SearchResult 模型