Q:站内搜索为什么不能使用Like模糊查找
A:模糊契合度太低,匹配关键字之间不能含有其他内容。最重要的是它会造成全表扫描,效率底下,即使使用视图,也会造成数据库服务器"亚历山大"
Lucene简介:
Lucene.NET只是一个全文检索开发包,不是一个成型的搜索引擎
它提供了类似SQLServer数据库正式版中的全文检索功能的索引库
你把数据扔给Lucene.Net,【Lucene.Net只针对文本信息建立索引,所以他只接收文本信息,如果不是文本信息,则要转换为文本信息】它会将文本内容分词后保存在索引库中,当用户输入关键字提交查询时,Lucene.Net从索引库中检索关键字数据,所以搜索速度非常快,适合于用户开发自己站内的搜索引擎
Q:分词
A:即将"不是所有痞子都叫一毛"文本内容通过分词算法 分割成为“不是” “所有” “痞子” “都” “叫” "一毛" 。 但是Lucene.Net内置分词算法对中文支持不是很好,以下会使用国内较为流行的分词算法 -- 盘古分词
以下是运行图解:
下面以用户查询数据库Book表 内容描述【对应字段名:ContentDescription】中包含其输入的关键字key的数据 演示Lucene.Net使用
运行界面效果如下:
本人使用的盘古分词版本为V2.3.1.0 Lucene.Net为2.9
在项目下新建Dict文件以及dll文件包含Lucene与盘古分词所需的组件及文件信息如图示
1、项目添加对dll文件夹中四个程序集的引用
2、添加图书搜索页面SearchBlogs.aspx代码如下:
<% @ Page Language="C#" AutoEventWireup="true" CodeBehind="SearchBook.aspx.cs" Inherits ="BookShop.Web.SearchBook" %> <! 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><form id="form1" runat="server"><asp : TextBox ID ="txtSerach" runat ="server" Width ="494px"></asp : TextBox><asp : Button ID ="btnSearch" runat ="server" onclick ="btnSearch_Click" Text ="搜索" /><asp : Button ID ="CreateView" runat ="server" onclick ="CreateView_Click" Text ="创建索引" /><div >< asp: Repeater ID ="Repeater1" runat ="server">< ItemTemplate>< table>< tbody>< tr>< td style ="font-size : small; color: red" width="650">< a id ="link_prd_name" href ='<% # Eval("Id","/book.aspx?id={0}") %> 'target ="_blank" name ="link_prd_name"><%# Eval( "Title") %></ a></ td></ tr>< tr>< td align ="left">< span style ="font-size : 12px; line-height: 20px"><%# Eval( "ContentDescription") %></ span ></ td></ tr></ tbody></ table></ ItemTemplate></ asp: Repeater ></div ></form > </ body> </ html>
3、后台调用
using System; using System.Collections.Generic; using System.IO; using BookShop.BLL; using Lucene.Net.Analysis.PanGu; using Lucene.Net.Documents; using Lucene.Net.Index; using Lucene.Net.Search; using Lucene.Net.Store; namespace BookShop.Web {public partial class SearchBook : System.Web.UI. Page {protected void Page_Load( object sender, EventArgs e) {}//创建索引事件 可以防止在用户点击查询事件前执行 去掉页面中的"创建索引"按钮protected void CreateView_Click( object sender, EventArgs e) {string indexPath = @"C:\luceneTest" ; //索引文档保存位置FSDirectory directory = FSDirectory .Open( new DirectoryInfo (indexPath), new NativeFSLockFactory ());bool isUpdate = IndexReader .IndexExists(directory); //是否存在索引库文件夹以及索引库特征文件if (isUpdate) {//如果索引目录被锁定(比如索引过程中程序异常退出或另一进程在操作),则解锁if (IndexWriter .IsLocked(directory)) {IndexWriter .Unlock(directory);}}//创建索引库对象 new PanGuAnalyzer()指定使用盘古分词进行切词IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer (), !isUpdate, Lucene.Net.Index.IndexWriter . MaxFieldLength.UNLIMITED);BooksManager bookManager = new BooksManager();List <Model.Books > bookList = bookManager.GetModelList( "" );foreach (var book in bookList) {Document document = new Document(); //new 一篇文档 对象//所有字段的值都将以字符串类型保存//Field.Store表示是否保存字段原值。指定Field.Store.YE的字段在检索时才能用document.Get取出来值 NOT_ANALYZED指定不按照分词后的结果保存document.Add( new Field ( "id", book.Id.ToString(), Field .Store .YES, Field .Index .NOT_ANALYZED));document.Add( new Field ( "title", book.Title, Field .Store .YES, Field .Index .ANALYZED, Lucene.Net.Documents.Field .TermVector .WITH_POSITIONS_OFFSETS));//Field.Index. ANALYZED指定文章内容按照分词后结果保存 否则无法实现后续的模糊查找 WITH_POSITIONS_OFFSETS指示不仅保存分割后的词 还保存词之间的距离document.Add( new Field ( "content", book.ContentDescription, Field .Store .YES, Field. Index .ANALYZED, Lucene.Net.Documents.Field .TermVector .WITH_POSITIONS_OFFSETS));writer.AddDocument(document); //文档写入索引库 }writer.Close();directory.Close(); //不要忘了Close,否则索引结果搜不到 }protected void btnSearch_Click( object sender, EventArgs e) {string indexPath = @"C:\luceneTest" ;FSDirectory directory = FSDirectory .Open( new DirectoryInfo (indexPath), new NoLockFactory ());IndexReader reader = IndexReader .Open(directory, true);IndexSearcher searcher = new IndexSearcher(reader); //Index:索引//搜索条件PhraseQuery query = new PhraseQuery();//把用户输入的关键字进行分词foreach (string word in Common.SplitContent .SplitWords(txtSerach.Text.ToLower())) {query.Add( new Term ( "content", word));}query.SetSlop(100); //指定关键词相隔最大距离//TopScoreDocCollector盛放查询结果的容器TopScoreDocCollector collector = TopScoreDocCollector .create(1000, true );searcher.Search(query, null , collector);//根据query查询条件进行查询,查询结果放入collector容器//TopDocs 指定0到GetTotalHits() 即所有查询结果中的文档ScoreDoc [] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;//展示数据实体对象集合List <Model.Books > bookResult = new List <Model.Books >();for (int i = 0; i < docs.Length; i++) {//需要获得文档的详细内容的时候通过searcher.Doc来根据文档id来获得文档的详细内容对象Documentint docId = docs[i].doc;//得到查询结果文档的id(Lucene内部分配的id)Document doc = searcher.Doc(docId);//找到文档id对应的文档详细信息Model. Books book = new Model. Books();book.Title = doc.Get( "title" );//book.ContentDescription = doc.Get("content");//未使用高亮//搜索关键字高亮显示book.ContentDescription = Common.SplitContent .HightLight(txtSerach.Text, doc.Get("content" ));book.Id = Convert .ToInt32(doc.Get("id" ));bookResult.Add(book);}//设置Repeater1 绑定查询结果集合Repeater1.DataSource = bookResult;Repeater1.DataBind();}} }
4、使用到的公共类 Common下的SplitContent类
using System.Collections.Generic; using System.IO; using Lucene.Net.Analysis; using Lucene.Net.Analysis.PanGu; using PanGu; namespace BookShop.Web.Common {public class SplitContent {public static string[] SplitWords( string content) {List <string > strList = new List <string >();Analyzer analyzer = new PanGuAnalyzer();TokenStream tokenStream = analyzer.TokenStream("" , new StringReader (content));Lucene.Net.Analysis. Token token = null ;while ((token = tokenStream.Next()) != null ) { //Next继续分词 直至返回nullstrList.Add(token.TermText()); //得到分词后结果 }return strList.ToArray();}//需要添加PanGu.HighLight.dll的引用/// <summary>/// 搜索结果高亮显示/// </summary>/// <param name="keyword"> 关键字 </param>/// <param name="content"> 搜索结果 </param>/// <returns> 高亮后结果 </returns>public static string HightLight( string keyword, string content) {//创建HTMLFormatter,参数为高亮单词的前后缀PanGu.HighLight. SimpleHTMLFormatter simpleHTMLFormatter =new PanGu.HighLight.SimpleHTMLFormatter ( "<font color=\"red\"><b>", "</b></font>" );//创建 Highlighter ,输入HTMLFormatter 和 盘古分词对象SemgentPanGu.HighLight. Highlighter highlighter =new PanGu.HighLight.Highlighter (simpleHTMLFormatter,new Segment ());//设置每个摘要段的字符数highlighter.FragmentSize = 50;//获取最匹配的摘要段return highlighter.GetBestFragment(keyword, content);}} }
5、使用Dict、Dll文件夹以及盘古分词的开发文档点击下载 实际应用中当然不会存在上图中的创建索引按钮 而且索引需随数据库数据同步更新 本章暂不介绍
http://blog.csdn.net/wangyizhi58/article/details/8705172