Loading

使用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 模型

     

posted @ 2015-04-28 16:54  WeihanLi  阅读(948)  评论(1编辑  收藏  举报