Lucene.net是Lucene的.net移植版本,在较早之前是比较受欢迎的一个开源的全文检索引擎开发包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎。

例子的组件版本

Lucene.Net:3.0.3.0

盘古分词:2.4.0.0

分词例子

  • 分词是核心算法,将完整的句子分词成若干个词或字;同时它只能处理文本信息,非文本信息只能转换成为文本信息,无法转换的只能放弃。
  • 所有供全文搜索的要先写入索引库,索引库可以看成存放数据的数据库
  • 搜索对象建立的时候(比如文章),写入数据库的同时,也要写入索引,也就是各存一份,检索的时候直接从索引库中检索。

Lucene.net有内置的分词算法,所有分词算法都继承Analyzer类;但对中文是按照单个字进行分词的,显然满足不了日常需求,所以常用到其他分词算法如盘古分词。

盘古分词下载后有以下dll内容

PanGu.dll :核心组件

PanGu.Lucene.Analyzer.dll :盘古分词针对Lucene.net 的接口组件,貌似词库写死在了dll文件里,没有配置词库的话,会读取dll里面的,否则直接读取配置的词库。

PanGu.HighLight.dll:高亮组件

PanGu.xml:xml文件配置,其中DictionaryPath 指明字典词库所在目录,可以为相对路径也可以为绝对路径

所需词库(并设置"复制到输出目录"属性):

简单分词只引入PanGu.Lucene.Analyzer.dll 即可,例子如下:

        [HttpPost]
public ActionResult Cut_2(string str)
{
//盘古分词
StringBuilder sb = new StringBuilder(); Analyzer analyzer = new PanGuAnalyzer(); TokenStream tokenStream = analyzer.TokenStream("", new StringReader(str)); ITermAttribute item = tokenStream.GetAttribute<ITermAttribute>(); while (tokenStream.IncrementToken()) {
sb.Append(item.Term + "|"); }
tokenStream.CloneAttributes();
analyzer.Close();
return Content(sb.ToString());
}

效果如下:

完整例子

项目前期准备:

  • 引入所需的三个dll
  • 在项目下放入PanGu.xml默认配置文件,与PanGu.dll不要在同一目录
  • 在项目下建立LuceneIndex文件夹用来存放索引数据
  • 在项目下建立Dict文件存放词典:Dict文件目录为默认词典文件目录,如不在Dict文件下,要在PanGu.xml中的DictionaryPath 指明字典词库所在目录
  1. 在进程启动时,需要对盘古分词进行初始化,初始化的调用代码如下(字典文件如果在Dict文件夹下,同时为默认配置,可以不用指定xml文件):
PanGu.Segment.Init(@"D:\seo_lucene.net_demo\bin\PanGu\PanGu.xml");
//或
PanGu.Segment.Init();

  2.创建索引

      //索引地址
      string indexPath = @"D:\学习代码\Seo-Lucene.Net\seo_lucene.net_demo\bin\LuceneIndex";

       /// <summary>
/// 索引目录
/// </summary>
public Lucene.Net.Store.Directory directory
{
get
{
//创建索引目录
if (!System.IO.Directory.Exists(indexPath))
{
System.IO.Directory.CreateDirectory(indexPath);
}
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());
return directory;
} }
        /// <summary>
/// 创建索引
/// </summary>
private void CreateIndex()
{
bool isExists = IndexReader.IndexExists(directory);//判断索引库是否存在
if (isExists)
{
//如果因异常情况索引目录被锁定,先解锁
//Lucene.Net每次操作索引库之前会自动加锁,在close的时候会自动解锁
//不能多线程执行,只能处理意外被永远锁定的情况
if (IndexWriter.IsLocked(directory))
{
IndexWriter.Unlock(directory);//解锁
}
} //IndexWriter第三个参数:true指重新创建索引,false指从当前索引追加,第一次新建索引库true,之后直接追加就可以了
IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isExists, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED); //Field.Store.YES:存储原文并且索引
//Field.Index. ANALYZED:分词存储
//Field.Index.NOT_ANALYZED:不分词存储
//一条Document相当于一条记录
//所有自定义的字段都是string
try
{
//以下语句可通过id判断是否存在重复索引,存在则删除,如果不存在则删除0条
//writer.DeleteDocuments(new Term("id", "1"));//防止存在的数据
//writer.DeleteDocuments(new Term("id", "2"));//防止存在的数据
//writer.DeleteDocuments(new Term("id", "3"));//防止存在的数据 //或是删除所有索引
writer.DeleteAll();
writer.Commit();
//是否删除成功
var IsSuccess = writer.HasDeletions(); Document doc = new Document();
doc.Add(new Field("id", "", Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("title", "三国演义", Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
doc.Add(new Field("Content", "刘备、云长、翼德点精兵三千,往北海郡进发。", Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
writer.AddDocument(doc); doc = new Document();
doc.Add(new Field("id", "", Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("title", "西游记", Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
doc.Add(new Field("Content", "话表齐天大圣到底是个妖猴,唐三藏。", Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
writer.AddDocument(doc); doc = new Document();
doc.Add(new Field("id", "", Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("title", "水浒传", Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
doc.Add(new Field("Content", "梁山泊义士尊晁盖 郓城县月夜走刘唐。", Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
writer.AddDocument(doc); }
catch (FileNotFoundException fnfe)
{
throw fnfe;
}
catch (Exception ex)
{
throw ex;
}
finally
{
writer.Optimize();
writer.Dispose();
directory.Dispose();
} }

   3.搜索

        /// <summary>
/// 搜索
/// </summary>
/// <param name="txtSearch">搜索字符串</param>
/// <param name="id">当前页</param>
/// <returns></returns>
[HttpGet]
public ActionResult Search(string txtSearch,int id=)
{
        //最大显示条数,用于分页
int pageNum = ;
        //当前页,用于分页
int currentPageNo = id;
IndexSearcher search = new IndexSearcher(directory, true);
BooleanQuery bQuery = new BooleanQuery(); //总的结果条数
List<Article> list = new List<Article>();
int recCount = ;
//处理搜索关键词
txtSearch = LuceneHelper.GetKeyWordsSplitBySpace(txtSearch); //多个字段查询 标题和内容title, content
MultiFieldQueryParser parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30,new string[] { "title", "Content" }, new PanGuAnalyzer());
Query query =parser.Parse(txtSearch); //Occur.Should 表示 Or 或查询, Occur.MUST 表示 and 与查询
bQuery.Add(query, Occur.MUST); if (bQuery != null && bQuery.GetClauses().Length > )
{
//盛放查询结果的容器
TopScoreDocCollector collector = TopScoreDocCollector.Create(, true);
//使用query这个查询条件进行搜索,搜索结果放入collector
search.Search(bQuery, null, collector);
recCount = collector.TotalHits;
//从查询结果中取出第m条到第n条的数据
ScoreDoc[] docs = collector.TopDocs((currentPageNo - ) * pageNum, pageNum).ScoreDocs;
//遍历查询结果
for (int i = ; i < docs.Length; i++)
{
//只有 Field.Store.YES的字段才能用Get查出来
Document doc = search.Doc(docs[i].Doc);
list.Add(new Article() {
Id = doc.Get("id"),
Title = LuceneHelper.CreateHightLight(txtSearch, doc.Get("title")),//高亮显示
Content = LuceneHelper.CreateHightLight(txtSearch, doc.Get("Content"))//高亮显示
});
}
}
//分页
PagedList<Article> plist = new PagedList<Article>(list, currentPageNo, pageNum, recCount);
plist.TotalItemCount = recCount;
plist.CurrentPageIndex = currentPageNo;
return View("Index", plist);
}

  4.其中LuceneHelper帮助类 

namespace seo_lucene.net_demo.Tools
{
public class LuceneHelper
{
/// <summary>
/// 处理关键字为索引格式
/// </summary>
/// <param name="keywords"></param>
/// <returns></returns>
public static string GetKeyWordsSplitBySpace(string keywords)
{
PanGuTokenizer ktTokenizer = new PanGuTokenizer();
StringBuilder result = new StringBuilder();
ICollection<WordInfo> words = ktTokenizer.SegmentToWordInfos(keywords); foreach (WordInfo word in words)
{
if (word == null)
{
continue;
}
result.AppendFormat("{0}^{1}.0 ", word.Word, (int)Math.Pow(, word.Rank));
}
return result.ToString().Trim();
}
//高亮显示
public static string CreateHightLight(string keywords, string Content)
{
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 Segment());
//设置每个摘要段的字符数
highlighter.FragmentSize = ;
//获取最匹配的摘要段
var result = highlighter.GetBestFragment(keywords, Content);
return string.IsNullOrEmpty(result) ? Content : result;
}
}
}

效果如下:

demo和lib包下载

全文检索-Lucene.net的更多相关文章

  1. 全文检索 Lucene(4)

    经过了前面几篇文章的学习,我们基本上可以适用Lucene来开发我们的站内搜索应用了.但是观察一下目前的主流的搜索引擎,我们会发现查询结果会有高亮的显示效果.所以,今天我们就来学习一下,给Lucene添 ...

  2. 全文检索 Lucene(3)

    看完前两篇博客之后,想必大家对于Lucene的使用都有了一个比较清晰的认识了.如果对Lucene的知识点还是有点模糊的话,个人建议还是先看看这两篇文章. 全文检索 Lucene(1) 全文检索 Luc ...

  3. 全文检索Lucene (2)

    接着全文检索Lucene (1) . 下面我们来深入的研究一下,如何使用Lucene! 从全文检索Lucene (1)中我们可以看出,Lucene就好比一个双向的工作流,一方面是对索引库的维护,另一方 ...

  4. Lucene 全文检索 Lucene的使用

    Lucene  全文检索  Lucene的使用 一.简介: 参考百度百科: http://baike.baidu.com/link?url=eBcEVuUL3TbUivRvtgRnMr1s44nTE7 ...

  5. 全文检索--Lucene & ElasticSearch

    全文检索--Lucene 2.1 全文检索和以前高级查询的比较 1.高级查询 缺点:1.like让数据库索引失效 2.每次查询都是查询数据库 ,如果访问的人比较多,压力也是比较大 2.全文检索框架:A ...

  6. [全文检索]Lucene基础入门.

    本打算直接来学习Solr, 现在先把Lucene的只是捋一遍. 本文内容: 1. 搜索引擎的发展史 2. Lucene入门 3. Lucene的API详解 4. 索引调优 5. Lucene搜索结果排 ...

  7. 全文检索Lucene (1)

    Lucene是apache开源的一个全文检索框架,很是出名.今天先来分享一个类似于HelloWorld级别的使用. 工作流程 依赖 我们要想使用Lucene,那就得先引用人家的jar包了.下面列举一下 ...

  8. 全文检索Lucene框架---查询索引

    一. Lucene索引库查询 对要搜索的信息创建Query查询对象,Lucene会根据Query查询对象生成最终的查询语法,类似关系数据库Sql语法一样Lucene也有自己的查询语法,比如:“name ...

  9. ]NET Core Lucene.net和PanGu分词实现全文检索

    Lucene.net和PanGu分词实现全文检索 Lucene.net(4.8.0) 学习问题记录五: JIEba分词和Lucene的结合,以及对分词器的思考   前言:目前自己在做使用Lucene. ...

随机推荐

  1. python类定义

    在我的收藏中有一篇特别详细的类讲解 此处部分内容引自:http://blog.sina.com.cn/s/blog_59b6af690101bfem.html class myclass: 'this ...

  2. Web资源认证原理

    Web服务器与浏览器之间的认证流程没有规定的步骤,根据不同的认证模式及鉴权方式可能会有不同的执行步骤.下图用一个最简单的流程了解整个认证过程是如何工作的,首先浏览器向服务器发起请求,然后服务器向浏览器 ...

  3. python字典作为统计记录工具

    1.python 利用字典作为计数项,统计指定项的个数 #!/usr/bin/python ta={} key = "test" if not key in ta:     ta[ ...

  4. (NO.00001)iOS游戏SpeedBoy Lite成形记(二十七)

    切换回Xcode,在GameScene.m中添加新的实例变量:_winLayer. 接下来在第一个选手到达终点时,我们可以完成选手胜利的动画特效了. 首先,在GameScene.m中添加一个新方法pl ...

  5. 学习pthreads,使用条件变量进行多线程之间的同步

    条件变量提供另一种多线程同步的方法.互斥量通过控制对共享数据的访问来同步任务.条件变量可以根据数据的值来同步任务.条件变量是当一个事件发生时发送信号的信号量.一旦事件发生,可能会有多个线程在等待信号, ...

  6. 网站开发进阶(二十六)js刷新页面方法大全

    js刷新页面方法大全 在项目开发过程中,需要实现刷新页面.经过学习,发现下面这条语句就可以轻松实现. location.reload(); // 刷新页面 有关刷新页面的其它方法,具体学习内容如下,有 ...

  7. 【一天一道LeetCode】#18. 4Sum

    一天一道LeetCode (一)题目 Given an array S of n integers, are there elements a, b, c, and d in S such that ...

  8. STM32F429学习笔记(一)触屏工程Keil建立

    由于原来的STM32F103ZET6的flash坏掉了,所以又买了一块STM32F429DISCOVERY,这块板子非常不错,基于Cortex-M4内核,自带一块2.4寸TFT触屏,主频为180M,且 ...

  9. linux设备和驱动加载的先后顺序

    点击打开链接 Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢. Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有 ...

  10. OAF中的MASTER-DETAIL关系

    在日常开发中,我们经常会遇到头行结构,并且要求打开界面,行是隐藏的,点击头上的"显示"按钮,才要求头对应的行信息全部显示出来,这样,我们就用到了Master-Detail结构. 下 ...