使用Lucene.NET实现简单的站内搜索
使用Lucene.NET实现简单的站内搜索
- 导入Lucene.NET 开发包
Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene.Net 是 .NET 版的Lucene。
你可以在这里下载到最新的Lucene.NET
- 创建索引、更新索引、删除索引

- 搜索,根据索引查找

using System;
using Lucene.Net.Store;
using Lucene.Net.Index;
using Lucene.Net.Analysis.PanGu;
using Lucene.Net.Documents; namespace BLL
{
class IndexHelper
{
/// <summary>
/// 日志小助手
/// </summary>
static Common.LogHelper logger = new Common.LogHelper(typeof(SearchBLL));
/// <summary>
/// 索引保存的位置,保存在配置文件中从配置文件读取
/// </summary>
static string indexPath = Common.ConfigurationHelper.AppSettingMapPath("IndexPath"); /// <summary>
/// 创建索引文件或更新索引文件
/// </summary>
/// <param name="item">索引信息</param>
public static void CreateIndex(Model.HelperModel.IndexFileHelper item)
{
try
{
//索引存储库
FSDirectory directory = FSDirectory.Open(new System.IO.DirectoryInfo(indexPath), new NativeFSLockFactory());
//判断索引是否存在
bool isUpdate = IndexReader.IndexExists(directory);
if (isUpdate)
{
//如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁
if (IndexWriter.IsLocked(directory))
{
//解锁索引库
IndexWriter.Unlock(directory);
}
}
//创建IndexWriter对象,添加索引
IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
//获取新闻 title部分
string title = item.FileTitle;
//获取新闻主内容
string body = item.FileContent;
//为避免重复索引,所以先删除number=i的记录,再重新添加
//尤其是更新的话,更是必须要先删除之前的索引
writer.DeleteDocuments(new Term("id", item.FileName));
//创建索引文件 Document
Document document = new Document();
//只有对需要全文检索的字段才ANALYZED
//添加id字段
document.Add(new Field("id", item.FileName, Field.Store.YES, Field.Index.NOT_ANALYZED));
//添加title字段
document.Add(new Field("title", title, Field.Store.YES, Field.Index.NOT_ANALYZED));
//添加body字段
document.Add(new Field("body", body, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
//添加url字段
document.Add(new Field("url", item.FilePath, Field.Store.YES, Field.Index.NOT_ANALYZED));
//写入索引库
writer.AddDocument(document);
//关闭资源
writer.Close();
//不要忘了Close,否则索引结果搜不到
directory.Close();
//记录日志
logger.Debug(String.Format("索引{0}创建成功",item.FileName));
}
catch (SystemException ex)
{
//记录错误日志
logger.Error(ex);
throw;
}
catch (Exception ex)
{
//记录错误日志
logger.Error(ex);
throw;
}
} /// <summary>
/// 根据id删除相应索引
/// </summary>
/// <param name="guid">要删除的索引id</param>
public static void DeleteIndex(string guid)
{
try
{
////索引存储库
FSDirectory directory = FSDirectory.Open(new System.IO.DirectoryInfo(indexPath), new NativeFSLockFactory());
//判断索引库是否存在索引
bool isUpdate = IndexReader.IndexExists(directory);
if (isUpdate)
{
//如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁
if (IndexWriter.IsLocked(directory))
{
IndexWriter.Unlock(directory);
}
}
IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
//删除索引文件
writer.DeleteDocuments(new Term("id", guid));
writer.Close();
directory.Close();//不要忘了Close,否则索引结果搜不到
logger.Debug(String.Format("删除索引{0}成功", guid));
}
catch (Exception ex)
{
//记录日志
logger.Error(ex);
//抛出异常
throw;
}
}
}
}IndexHelper 添加、更新、删除索引
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.PanGu;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Model.HelperModel;
using System;
using System.Collections.Generic; namespace BLL
{
public static class SearchBLL
{
//一个类中可能会有多处输出到日志,多处需要记录日志,常将logger做成static 静态变量
/// <summary>
/// 日志助手
/// </summary>
static Common.LogHelper logger = new Common.LogHelper(typeof(SearchBLL));
/// <summary>
/// 索引保存位置
/// </summary>
static string indexPath = Common.ConfigurationHelper.AppSettingMapPath("IndexPath");
/// <summary>
/// 搜索
/// </summary>
/// <param name="keywords">用户搜索的关键词</param>
/// <returns>返回搜索的结果</returns>
public static List<SearchResult> Search(string keywords)
{
try
{
//索引存储库
FSDirectory directory = FSDirectory.Open(new System.IO.DirectoryInfo(indexPath), new NoLockFactory());
//创建IndexReader对象
IndexReader reader = IndexReader.Open(directory, true);
//创建IndexSearcher对象
IndexSearcher searcher = new IndexSearcher(reader);
//新建PhraseQuery 查询对象
PhraseQuery query = new PhraseQuery();
//把用户输入的关键词进行拆词
foreach (string word in SplitWord(keywords))
{
//添加搜索关键词
query.Add(new Term("body", word));
}
//设置分词间距为100字之内
query.SetSlop();
TopScoreDocCollector collector = TopScoreDocCollector.create(, true);
//根据查询条件查询结果
searcher.Search(query, null, collector);
//搜索到的ScoreDoc结果
ScoreDoc[] docs = collector.TopDocs(, collector.GetTotalHits()).scoreDocs;
//保存搜索结果的list
List<SearchResult> listResult = new List<SearchResult>();
for (int i = ; i < docs.Length; i++)
{
//取到文档的编号(主键,这个是Lucene .net分配的)
//检索结果中只有文档的id,如果要取Document,则需要Doc再去取
//降低内容占用
int docId = docs[i].doc;
//根据id找Document
Document doc = searcher.Doc(docId);
string number = doc.Get("id");
string title = doc.Get("title");
string body = doc.Get("body");
string url = doc.Get("url");
//建立一个搜索结果对象
SearchResult result = new SearchResult();
result.Number = number;
result.Title = title;
result.BodyPreview = Preview(body, keywords);
result.Url = url;
//添加到结果列表
listResult.Add(result);
}
if (listResult.Count == )
{
return null;
}
else
{
return listResult;
}
}
catch (SystemException ex)
{
logger.Error(ex);
return null;
}
catch (Exception ex)
{
logger.Error(ex);
return null;
}
} /// <summary>
/// 获取内容预览
/// </summary>
/// <param name="body">内容</param>
/// <param name="keyword">关键词</param>
/// <returns></returns>
private static string Preview(string body, string keyword)
{
//创建HTMLFormatter,参数为高亮单词的前后缀
PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
//创建 Highlighter ,输入HTMLFormatter 和 盘古分词对象Semgent
PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new PanGu.Segment());
//设置每个摘要段的字符数
highlighter.FragmentSize = ;
//获取最匹配的摘要段
string bodyPreview = highlighter.GetBestFragment(keyword, body);
return bodyPreview;
} /// <summary>
/// 盘古分词,对用户输入的搜索关键词进行分词
/// </summary>
/// <param name="str">用户输入的关键词</param>
/// <returns>分词之后的结果组成的数组</returns>
private static string[] SplitWord(string str)
{
List<string> list = new List<string>();
Analyzer analyzer = new PanGuAnalyzer();
TokenStream tokenStream = analyzer.TokenStream("", new System.IO.StringReader(str));
Lucene.Net.Analysis.Token token = null;
while ((token = tokenStream.Next()) != null)
{
list.Add(token.TermText());
}
return list.ToArray();
}
}
}Search 通过查找索引实现搜索
namespace Model.HelperModel
{
public class SearchResult
{
public string Number { get; set; } public string Title { get; set; } public string BodyPreview { get; set; } public string Url { get; set; }
}
}SearchResult 模型
使用Lucene.NET实现简单的站内搜索的更多相关文章
- es简单打造站内搜索
最近挺忙的,在外出差,又同时干两个项目.白天一个晚上一个,特别是白天做的项目,马上就要上线了,在客户这里 三天两头开会,问题很多真的很想好好静下来怼代码,半夜做梦都能fix bugs~ 和客户交流真的 ...
- 基于lucene.net 和ICTCLAS2014的站内搜索的实现1
Lucene.net是一个搜索引擎的框架,它自身并不能实现搜索.须要我们自己在当中实现索引的建立,索引的查找.全部这些都是依据它自身提供的API来实现.Lucene.net本身是基于java的,可是经 ...
- Lucene.net站内搜索—4、搜索引擎第一版技术储备(简单介绍Log4Net、生产者消费者模式)
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Lucene.net站内搜索—3、最简单搜索引擎代码
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Lucene.net站内搜索—6、站内搜索第二版
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Lucene.net站内搜索—5、搜索引擎第一版实现
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Lucene.net站内搜索—2、Lucene.Net简介和分词
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Lucene.net站内搜索—1、SEO优化
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- 站内搜索——Lucene +盘古分词
为了方便的学习站内搜索,下面我来演示一个MVC项目. 1.首先在项目中[添加引入]三个程序集和[Dict]文件夹,并新建一个[分词内容存放目录] Lucene.Net.dll.PanGu.dll.Pa ...
随机推荐
- JRE和JDK
转自:http://www.cnblogs.com/myitm/archive/2011/05/03/2035942.html 很多程序员已经干了一段时间java了依然不明白jdk与jre的区别. ...
- CSS布局:Float布局过程与老生常谈的三栏布局
原文见博客主站,欢迎大家去评论. 使用CSS布局网页,那是前端的基本功了,什么两栏布局,三栏布局,那也是前端面试的基本题了.一般来说,可以使用CSSposition属性进行布局,或者使用CSSfloa ...
- Qt4.8.6 Embedded Linux 的编译与移植
最近买了个飞凌ok6410 的开发板,于是在其中搭建qt4.8.6运行环境.费了两三天时间,主要还是对Linux系统的生疏,在一些问题上徘徊很久,在这里做一些过程笔记.烧写ARM-Linux系统,根据 ...
- Tips9: Destroy( )函数中的 延迟摧毁 功能
你知道Object.Destroy()函数吗?在脚本中用来摧毁一个游戏物体或组件,可是你知道他能在执行后延迟一段时间后才摧毁物体吗,其实很简单: using UnityEngine; public c ...
- 网站跨站点单点登录实现--cookie
至于什么是单点登录,举个例子,如果你登录了msn messenger,访问hotmail邮件就不用在此登录.一般单点登录都需要有一个独立的登录站点,一般具有独立的域名,专门的进行注册,登录,注销等操作 ...
- Android学习笔记之ConnectivityManager+NetWorkInfo
PS:眼看就要开学了,该收收心了. 学习内容: 1.ConnecivityManager 2.NetWorkInfo ConnectivityManger:网络连接管理者,用于管理Android设 ...
- Android 学习笔记之ContentProvider实现数据共享....
PS:最近听老师说打算让我参与企业的app制作,让我加快学习的进度...好吧,貌似下周还有考试...貌似实验室这个app也要做...暂时不管了...那就只能加快进度了,感觉略微的有点激动和紧张,总算是 ...
- 深入浅出 JavaScript 中的 this
在 Java 等面向对象的语言中,this 关键字的含义是明确且具体的,即指代当前对象.一般在编译期确定下来,或称为编译期绑定.而在 JavaScript 中,this 是动态绑定,或称为运行期绑定的 ...
- 点餐APP 冲刺三总结
一转眼所有的冲刺都完成了,而今次的冲刺主要是完善数据库,而我们 也成功地实现了,虽然过程很艰辛,但是我们每一个人都学习到了很多新 知识,这是最好的收获.因为今学期没有软件工程的课程,所以大家都是 利用 ...
- 组合数学 - 母函数的运用 --- hdu 1709 :The Balance
The Balance Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...