站内搜索——Lucene +盘古分词
为了方便的学习站内搜索,下面我来演示一个MVC项目。
1.首先在项目中【添加引入】三个程序集和【Dict】文件夹,并新建一个【分词内容存放目录】
Lucene.Net.dll、PanGu.dll、PanGu.Lucene.Analyzer.dll
链接:http://pan.baidu.com/s/1eS6W8s6 密码:ds8b
链接:链接:http://pan.baidu.com/s/1geYyDnt 密码:8rq4
2.建立Search控制器,并转到Index界面写入如下内容:
PS:VS有问题,波浪号由他去吧,,,
----------后台语句-------
->创建索引语句
public ActionResult SearchContent()
{
//首先根据name区分是点击的哪个按钮
if (!String.IsNullOrEmpty(Request.Form["btnSearch"]))//执行搜索
{ }
else//创建索引
{
CreateSearchIndex();//调用创建索引语句
}
return Content("OK");
}
//创建索引语句
public void CreateSearchIndex()
{
string indexPath = @"H:\lucenedir";//注意和磁盘上文件夹的大小写一致,否则会报错。将创建的分词内容放在该目录下
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());
bool isUpdate = IndexReader.IndexExists(directory);//判断索引库是否存在
if (isUpdate)
{
//如果索引目录被锁定(比如索引过程中程序异常退出),则首先解锁
//Lucene.Net在写索引库之前会自动加锁,在close的时候会自动解锁
//不能多线程执行,只能处理意外被永远锁定的情况
if (IndexWriter.IsLocked(directory))
{
IndexWriter.Unlock(directory);//un-否定。强制解锁
}
}
IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
//-------调用业务层拿到所有的数据
Search.BLL.UserGUIDBll bll = new Search.BLL.UserGUIDBll();
List<Search.Model.UserInfo> list=bll.SelectAll();
foreach (UserInfo item in list)
{
Document document = new Document();//一条Document相当于一条记录
document.Add(new Field("id",item.UserId.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//每个Document可以有自己的属性(字段),所有字段名都是自定义的,值都是string类型
//想给用户展示什么就往词库里面添加什么
document.Add(new Field("title",item.UserName, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
document.Add(new Field("content", item.UserContent, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
writer.AddDocument(document); }
writer.Close();//会自动解锁
directory.Close();//不要忘了Close,否则索引结果搜不到
}
执行创建索引语句,将看到分词内容文件夹里面将多一些东西,这些就是用来以后检索的
->执行索引语句
public ActionResult SearchContent()
{
//首先根据name区分是点击的哪个按钮
if (!String.IsNullOrEmpty(Request.Form["btnSearch"]))//执行搜索
{
List<ViewSearchContentModel> recList=SearchBookContent();
ViewData["searchList"] = recList;
return View("Index");
}
else//创建索引
{
CreateSearchIndex();//调用创建索引语句 }
return Content("OK");
}
SearchBookContent类:
//执行索引语句
public List<ViewSearchContentModel> SearchBookContent()
{
string indexPath = @"H:\lucenedir"; //lucene存数据的路径
string searchTxt = Request.Form["txtContent"];//获取用户输入的内容
//将用户输入的内容进行分词
List<string> kw=SearchController.GetPanGuWord(searchTxt); //string kw = "没有";
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
IndexReader reader = IndexReader.Open(directory, true);
IndexSearcher searcher = new IndexSearcher(reader);
PhraseQuery query = new PhraseQuery();//查询条件
//query.Add(new Term("msg", kw));//where contains("msg",kw) 这里的msg对应上面的msg
foreach (string word in kw)//先用空格,让用户去分词,空格分隔的就是词“计算机 专业”
{
query.Add(new Term("content", word));//contains("msg",word)
}
query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了
TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器
searcher.Search(query, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector
//collector.GetTotalHits()总的结果条数
ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;//从查询结果中取出第m条到第n条的数据 List<ViewSearchContentModel> list = new List<ViewSearchContentModel>();
for (int i = 0; i < docs.Length; i++)//遍历查询结果
{
ViewSearchContentModel viewModel = new ViewSearchContentModel();
int docId = docs[i].doc;//拿到文档的id。因为Document可能非常占内存(DataSet和DataReader的区别)
//所以查询结果中只有id,具体内容需要二次查询
Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是Document
viewModel.Id = doc.Get("id");
viewModel.Title = doc.Get("title");
viewModel.Content = doc.Get("content");
list.Add(viewModel);
}
return list; }
class SearchResult
{
public int Id { get; set; }
public string Msg { get; set; }
}
//利用盘古分词对用户输入的内容进行分词
public static List<string> GetPanGuWord(string str)
{
List<string> list=new List<string>();
Analyzer analyzer = new PanGuAnalyzer();
TokenStream tokenStream = analyzer.TokenStream("", new StringReader(str));
Lucene.Net.Analysis.Token token = null;
while ((token = tokenStream.Next()) != null)
{
list.Add(token.TermText());
// Console.WriteLine(token.TermText());
}
return list;
}
ViewSearchContentModel类:(这个类定义在MVC中的Model里面的,视图要展示啥数据,这里就定义什么)
->前台修改如下:
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>文档搜索</title>
</head>
<body>
<div>
<form method="post" action="/Search/SearchContent">
请输入搜索的条件:<input type="text" name="txtContent" />
<input type="submit" value="搜索" name="btnSearch"/>
<input type="submit" value="创建索引库" name="btnCreate"/>
</form>
<table>
<tbody>
<%if (ViewData["searchList"] != null)
{
foreach (站内搜索2.Models.ViewSearchContentModel item in (List<站内搜索2.Models.ViewSearchContentModel>)ViewData["searchList"])
{%>
<tr><td><%=item.Id%></td><td><%=item.Title%></td><td><%=item.Content%></td></tr>
<% } }
%>
</tbody>
</table> </div>
</body>
</html>
-----这时基本搜索功能就实现了,接下来实现高亮显示-------
1.添加或引入PanGu.HighLight和PanGu.HighLight.pdb
链接:http://pan.baidu.com/s/1eS6W8s6 密码:ds8b
创建一个Common文件夹,并在里面建立一个WebCommon类
代码如下:(这个类中参数keyworkds就是要高亮显示的值,content就是返回的内容,这样在搜索结果中调用这个类就能实现高亮)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using PanGu.HighLight;
using PanGu; namespace 站内搜索2.Common
{
public class WebCommon
{
public static string CreateHighLight(string keywords, string content)
{
SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font style='color:red'>", "</font>");
Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new Segment());
//设置每个摘要的字符数
highlighter.FragmentSize = 150;
return highlighter.GetBestFragment(keywords, content);
}
}
}
在搜索结果中调用这个类:
// viewModel.Content = doc.Get("content");
viewModel.Content = Common.WebCommon.CreateHighLight(Request["txtContent"], doc.Get("content"));
写到这先放张效果图吧:
注意:有的时候我们使用razor引擎,会发生自动编码问题,为了正常显示,我们可以这样写:@MVCHtmlString.Create(item.Title)
JS侧栏分享代码:
<!-- JiaThis Button BEGIN -->
<script type="text/javascript" src="http://v3.jiathis.com/code/jiathis_r.js?move=0&btn=r4.gif" charset="utf-8"></script>
<!-- JiaThis Button END -->
最后再补充一下分词工具使用方式:
站内搜索源码下载:链接:http://pan.baidu.com/s/1o8IlAZK 密码:0gwf
站内搜索——Lucene +盘古分词的更多相关文章
- 完整的站内搜索Demo(Lucene.Net+盘古分词)
前言 首先自问自答几个问题,以让各位看官了解写此文的目的 什么是站内搜索?与一般搜索的区别? 很多网站都有搜索功能,很多都是用SQL语句的Like实现的,但是Like无法做到模糊匹配(例如我搜索“.n ...
- 完整的站内搜索实战应用(Lucene.Net+盘古分词)
首先自问自答几个问题,以让各位看官了解写此文的目的 什么是站内搜索?与一般搜索的区别? 多网站都有搜索功能,很多都是用SQL语句的Like实现的,但是Like无法做到模糊匹配(例如我搜索". ...
- Lucene.net站内搜索—2、Lucene.Net简介和分词
目录 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站内搜索—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实现简单的站内搜索
使用Lucene.NET实现简单的站内搜索 导入Lucene.NET 开发包 Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和 ...
- Lucene.Net 站内搜索
Lucene.Net 站内搜索 一 全文检索: like查询是全表扫描(为性能杀手)Lucene.Net搜索引擎,开源,而sql搜索引擎是收费的Lucene.Net只是一个全文检索开发包(只是帮我们 ...
- 基于lucene.net 和ICTCLAS2014的站内搜索的实现1
Lucene.net是一个搜索引擎的框架,它自身并不能实现搜索.须要我们自己在当中实现索引的建立,索引的查找.全部这些都是依据它自身提供的API来实现.Lucene.net本身是基于java的,可是经 ...
随机推荐
- AngularJS 拦截器
在需要进行身份验证时,在请求发送给服务器之前或者从服务器返回时对其进行拦截,是比较好的实现手段. 例如,对于身份验证,如果服务器返回401状态码,将用户重定向到登录页面. AngularJS通过拦截器 ...
- .NET对象的内存布局
每个虚拟机都有它自己的对象布局,本文我们将针对sscli源码和windbg调试器来查看不同类型的.net对象布局. 在.net虚拟机里,每个对象都需要保存这些信息: 对象的类型: 对象实例的成员属性( ...
- 新手ui设计师必备——切图规范
图文并茂,浅显易懂. 使用markman标注. 资源链接: 图片来自http://www.ui.cn/detail/56347.html 本文作者starof,因知识本身在变化,作者也在不断学习成长, ...
- MMORPG大型游戏设计与开发(客户端架构 part6 of vegine)
客户端的变量模块部分主要是将一些常用可变的值集中管理,如窗口的大小,是否开启音乐,音量的大小等等.这些变量通常会应该到客户端的操作,一般来说变量改变的时候会调用一个回调进行处理.下面我们就看看该模块的 ...
- git 学习使用总结一(本地操作)
通过几天的学习,熟悉了 git 的一些常用命令,要用熟练和操作更复杂的功能还必须继续学习.不过 git 作为工具,它是用来提高我们的工作效率的工具,系统的学习之后可以暂且放放,等到以后实际项目中用到了 ...
- java 22 - 17 多线程之等待唤醒机制(接16)
先来一张图,看看什么叫做等待唤醒机制 接上一章的例子. 例子:学生信息的录入和获取 * 资源类:Student * 设置学生数据:SetThread(生产者) * 获取学生数据:GetThread( ...
- IE11下不能引入外部css的解决方法
原: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...
- NodeJS中的静态资源管理服务
欢迎大家指导与讨论 : ) 一.什么是静态资源 静态资源就是放在服务器中的特定的文件.比较常见的有.css,.png, .js的这一些后缀的文件.下图中的这个html页面便要获取到logo.png和a ...
- Html5 Egret游戏开发 成语大挑战(八)一般性二级页面处理
在游戏中,我们一般会有各种各样的二级页面,比如游戏暂停界面或者游戏结束界面,这些界面组成了对玩家交互主要手段,在游戏开发中,对于这些界面的coding组织是非常有学问的,如果倒退到十年前,游戏开发的老 ...
- ssh生成key不交互
ssh-keygen -t rsa -f ~/.ssh/id_rsa -P "" 首次执行不交互 第二次再次执行会让输入y