使用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();
    49. TopScoreDocCollector collector = TopScoreDocCollector.create(, true);
    50. //根据查询条件查询结果
    51. searcher.Search(query, null, collector);
    52. //搜索到的ScoreDoc结果
    53. ScoreDoc[] docs = collector.TopDocs(, collector.GetTotalHits()).scoreDocs;
    54. //保存搜索结果的list
    55. List<SearchResult> listResult = new List<SearchResult>();
    56. for (int i = ; 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 == )
    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 = ;
    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 模型

使用Lucene.NET实现简单的站内搜索的更多相关文章

  1. es简单打造站内搜索

    最近挺忙的,在外出差,又同时干两个项目.白天一个晚上一个,特别是白天做的项目,马上就要上线了,在客户这里 三天两头开会,问题很多真的很想好好静下来怼代码,半夜做梦都能fix bugs~ 和客户交流真的 ...

  2. 基于lucene.net 和ICTCLAS2014的站内搜索的实现1

    Lucene.net是一个搜索引擎的框架,它自身并不能实现搜索.须要我们自己在当中实现索引的建立,索引的查找.全部这些都是依据它自身提供的API来实现.Lucene.net本身是基于java的,可是经 ...

  3. Lucene.net站内搜索—4、搜索引擎第一版技术储备(简单介绍Log4Net、生产者消费者模式)

    目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...

  4. Lucene.net站内搜索—3、最简单搜索引擎代码

    目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...

  5. Lucene.net站内搜索—6、站内搜索第二版

    目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...

  6. Lucene.net站内搜索—5、搜索引擎第一版实现

    目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...

  7. Lucene.net站内搜索—2、Lucene.Net简介和分词

    目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...

  8. Lucene.net站内搜索—1、SEO优化

    目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...

  9. 站内搜索——Lucene +盘古分词

    为了方便的学习站内搜索,下面我来演示一个MVC项目. 1.首先在项目中[添加引入]三个程序集和[Dict]文件夹,并新建一个[分词内容存放目录] Lucene.Net.dll.PanGu.dll.Pa ...

随机推荐

  1. java之数组

    数组概述: 1.数组可以看成是多个相同数据类型数据的组合,对这些数据的统一管理. 2.数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量. 3.数组中的元素可以是任何类型 ...

  2. Mysql 导入数据,推荐Source命令,太快了

    http://jingyan.baidu.com/article/cbf0e500d15c762eab289362.html

  3. 一个代价11万的bug

    这个bug不是技术bug或者是程序bug,是典型的业务操作bug. 开发人员混淆了线上数据和本地测试数据,把线上数据切换到本地的数据做测试,结果对这些客户进行了资金调整...就导致了这个悲剧发生 早在 ...

  4. iOS 复选框做法

    -(void)checkboxClick:(UIButton *)btn{    btn.selected = !btn.selected;} - (void)viewDidLoad {UIButto ...

  5. Discuz & UCenter 修改手记 - 2014.12.19

    最近在整JAVA和UCENTER的东西,受限于项目架构需要,无法完全以UCENTER为中心,所以在对接过程中遇到了许多不愉快的事情.经历多番研究,终于解决了其中了两个大问题,现记录下来,以备日后查看. ...

  6. 快乐的JS正则表达式(三)

    ?的用途. 小任务:匹配一段网址如var str = "http://www.123.com/";注意http也可以是https var str = "http://i. ...

  7. Java后端书架

    本书架主要针对Java后端开发与架构. 更新记录:4.0版把第五部份-具体技术的书整块拿掉了.<TCP/IP详解 卷1:协议>出到了第二版,增加<SRE:Google运维解密> ...

  8. 自动化运维工具之 Ansible 介绍及安装使用

    一.初识Ansible 介绍: Absible 使用 模块(Modules)来定义配置任务.模块可以用标准脚本语言(Python,Bash,Ruby,等等)编写,这是一个很好的做法,使每个模块幂等.A ...

  9. SQL Server里因丢失索引造成的死锁

    在今天的文章里我想演示下SQL Server里在表上丢失索引如何引起死锁(deadlock)的.为了准备测试场景,下列代码会创建2个表,然后2个表都插入4条记录. -- Create a table ...

  10. 转载:第三弹!全球首个微信小程序(应用号)开发教程!通宵吐血赶稿,每日更新!

    感谢朋友们的支持!这两天博卡君收到了很多支持和安慰,也认识了很多志同道合的朋友.目前微信公布的工具和代码都不是正式版,随时有可能调整,大家先体验和学习为主吧.最近这个教程搞得我也心力交瘁了,虽然苦逼, ...