何為Lucene.Net?
Lucene.net是Lucene的.net移植版本,是一個(gè)開源的全文檢索引擎開發(fā)包迁霎,即它不是一個(gè)完整的全文檢索引擎肉盹,而是一個(gè)全文檢索引擎的架構(gòu),提供了完整的查詢引擎和索引引擎国拇。開發(fā)人員可以基于Lucene.net實(shí)現(xiàn)全文檢索的功能洛史。
Lucene.net是Apache軟件基金會(huì)贊助的開源項(xiàng)目,基于Apache License協(xié)議酱吝。
Lucene.net并不是一個(gè)爬行搜索引擎也殖,也不會(huì)自動(dòng)地索引內(nèi)容。我們得先將要索引的文檔中的文本抽取出來(lái)务热,然后再將其加到Lucene.net索引中忆嗜。標(biāo)準(zhǔn)的步驟是先初始化一個(gè)Analyzer、打開一個(gè)IndexWriter崎岂、然后再將文檔一個(gè)接一個(gè)地加進(jìn)去捆毫。一旦完成這些步驟,索引就可以在關(guān)閉前得到優(yōu)化冲甘,同時(shí)所做的改變也會(huì)生效绩卤。這個(gè)過(guò)程可能比開發(fā)者習(xí)慣的方式更加手工化一些,但卻在數(shù)據(jù)的索引上給予你更多的靈活性损合,而且其效率也很高省艳。
如何在C#中實(shí)現(xiàn)站內(nèi)搜索?
1.添加對(duì)以下dll的引用:
2.添加詞庫(kù)文件:包含Dict目錄下所有文件
3.如何創(chuàng)建索引:
///
/// 創(chuàng)建索引嫁审,將數(shù)據(jù)庫(kù)中的數(shù)據(jù)取出來(lái)給Lucene索引庫(kù)
///
protected void CreateContent()
{
string indexPath = @”C:/lucenedir”;//注意和磁盤上文件夾的大小寫一致跋炕,否則會(huì)報(bào)錯(cuò)。將創(chuàng)建的分詞內(nèi)容放在該目錄下律适。
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NativeFSLockFactory());//指定索引文件(打開索引目錄) FS指的是就是FileSystem
bool isUpdate = IndexReader.IndexExists(directory);//IndexReader:對(duì)索引進(jìn)行讀取的類辐烂。該語(yǔ)句的作用:判斷索引庫(kù)文件夾是否存在以及索引特征文件是否存在。
if (isUpdate)
{
//同時(shí)只能有一段代碼對(duì)索引庫(kù)進(jìn)行寫操作捂贿。當(dāng)使用IndexWriter打開directory時(shí)會(huì)自動(dòng)對(duì)索引庫(kù)文件上鎖纠修。
//如果索引目錄被鎖定(比如索引過(guò)程中程序異常退出),則首先解鎖(提示一下:如果我現(xiàn)在正在寫著已經(jīng)加鎖了厂僧,但是還沒(méi)有寫完扣草,這時(shí)候又來(lái)一個(gè)請(qǐng)求,那么不就解鎖了嗎?這個(gè)問(wèn)題后面會(huì)解決)
if (IndexWriter.IsLocked(directory))
{
IndexWriter.Unlock(directory);
}
}
IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);//向索引庫(kù)中寫索引辰妙。這時(shí)在這里加鎖鹰祸。
BLL.BookManager bll = new BLL.BookManager();
List list = bll.GetModelList(“”);
foreach (Model.Book model in list)
{
writer.DeleteDocuments(new Term(“id”,model.Id.ToString()));//刪除索引庫(kù)中原有的項(xiàng).
Document document = new Document();//表示一篇文檔。
//Field.Store.YES:表示是否存儲(chǔ)原值密浑。只有當(dāng)Field.Store.YES在后面才能用doc.Get(“number”)取出值來(lái).Field.Index. NOT_ANALYZED:不進(jìn)行分詞保存
document.Add(new Field(“id”, model.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
//Field.Index. ANALYZED:進(jìn)行分詞保存:也就是要進(jìn)行全文的字段要設(shè)置分詞 保存(因?yàn)橐M(jìn)行模糊查詢)
//Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS:不僅保存分詞還保存分詞的距離蛙婴。
document.Add(new Field(“title”, model.Title, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
document.Add(new Field(“msg”, model.ContentDescription, Field.Store.YES, Field.Index.ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
writer.AddDocument(document);
}
writer.Close();//會(huì)自動(dòng)解鎖。
directory.Close();//不要忘了Close尔破,否則索引結(jié)果搜不到
}
4.添加分詞方法:
///
/// 對(duì)用戶輸入的搜索的條件進(jìn)行分詞
///
///
///
public static string[] SplitWord(string str)
{
List list = new List();
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());
}
return list.ToArray();
}
4.搜索代碼實(shí)現(xiàn):
//搜索
protected void SearchContent()
{
string indexPath = @”C:/lucenedir”;//最好將該項(xiàng)放在配置文件中街图。
string kw = Request["txtContent"];
kw = kw.ToLower();
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());
IndexReader reader = IndexReader.Open(directory, true);
IndexSearcher searcher = new IndexSearcher(reader);
//搜索條件
PhraseQuery query = new PhraseQuery();
foreach (string word in Common.WebCommon.SplitWord(kw))//將用戶輸入的搜索內(nèi)容進(jìn)行了盤古分詞、
{
query.Add(new Term(“msg”, word));
}
query.SetSlop(100);//多個(gè)查詢條件的詞之間的最大距離.在文章中相隔太遠(yuǎn) 也就無(wú)意義.(例如 “大學(xué)生”這個(gè)查詢條件和”簡(jiǎn)歷”這個(gè)查詢條件之間如果間隔的詞太多也就沒(méi)有意義了懒构。)
//TopScoreDocCollector是盛放查詢結(jié)果的容器
TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
searcher.Search(query, null, collector);//根據(jù)query查詢條件進(jìn)行查詢餐济,查詢結(jié)果放入collector容器
ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;//得到所有查詢結(jié)果中的文檔,GetTotalHits():表示總條數(shù) TopDocs(300, 20);//表示得到300(從300開始),到320(結(jié)束)的文檔內(nèi)容. //可以用來(lái)實(shí)現(xiàn)分頁(yè)功能
List list = new List();
for (int i = 0; i < docs.Length; i++)
{
//
//搜索ScoreDoc[]只能獲得文檔的id,這樣不會(huì)把查詢結(jié)果的Document一次性加載到內(nèi)存中胆剧。降低了內(nèi)存壓力颤介,需要獲得文檔的詳細(xì)內(nèi)容的時(shí)候通過(guò)searcher.Doc來(lái)根據(jù)文檔id來(lái)獲得文檔的詳細(xì)內(nèi)容對(duì)象Document.
int docId = docs[i].doc;//得到查詢結(jié)果文檔的id(Lucene內(nèi)部分配的id)
Document doc = searcher.Doc(docId);//找到文檔id對(duì)應(yīng)的文檔詳細(xì)信息
SearchResult result = new SearchResult();
result.Msg =Common.WebCommon.Highlight(kw,doc.Get(“msg”));
result.Title = doc.Get(“title”);
result.Url = “/BookDeatail.apsx?id=” + doc.Get(“id”);
list.Add(result);
}
this.SearchRepeater.DataSource = list;
this.SearchRepeater.DataBind();
}
5.高亮顯示關(guān)鍵詞:
///
/// 對(duì)搜索的關(guān)鍵詞高亮顯示
///
///
///
///
public static string Highlight(string keyword, string content)
{
//創(chuàng)建HTMLFormatter,參數(shù)為高亮單詞的前后綴
PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter =
new PanGu.HighLight.SimpleHTMLFormatter(“”,
“”);
//創(chuàng)建 Highlighter ,輸入HTMLFormatter 和 盤古分詞對(duì)象Semgent
PanGu.HighLight.Highlighter highlighter =
new PanGu.HighLight.Highlighter(simpleHTMLFormatter,
new Segment());
//設(shè)置每個(gè)摘要段的字符數(shù)
highlighter.FragmentSize =100;
//獲取最匹配的摘要段
return highlighter.GetBestFragment(keyword, content);
}