Lucene.Net實(shí)現(xiàn)站內(nèi)搜索功能

何為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);

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赞赖,一起剝皮案震驚了整個(gè)濱河市滚朵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌前域,老刑警劉巖辕近,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異匿垄,居然都是意外死亡移宅,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門椿疗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)漏峰,“玉大人,你說(shuō)我怎么就攤上這事届榄∏城牵” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵铝条,是天一觀的道長(zhǎng)靖苇。 經(jīng)常有香客問(wèn)我,道長(zhǎng)班缰,這世上最難降的妖魔是什么贤壁? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮埠忘,結(jié)果婚禮上脾拆,老公的妹妹穿的比我還像新娘馒索。我一直安慰自己,他們只是感情好名船,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布双揪。 她就那樣靜靜地躺著,像睡著了一般包帚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上运吓,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天渴邦,我揣著相機(jī)與錄音,去河邊找鬼拘哨。 笑死谋梭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倦青。 我是一名探鬼主播瓮床,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼产镐!你這毒婦竟也來(lái)了隘庄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤癣亚,失蹤者是張志新(化名)和其女友劉穎丑掺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體述雾,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡街州,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玻孟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唆缴。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖黍翎,靈堂內(nèi)的尸體忽然破棺而出面徽,到底是詐尸還是另有隱情,我是刑警寧澤匣掸,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布斗忌,位于F島的核電站,受9級(jí)特大地震影響旺聚,放射性物質(zhì)發(fā)生泄漏织阳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一砰粹、第九天 我趴在偏房一處隱蔽的房頂上張望唧躲。 院中可真熱鬧造挽,春花似錦、人聲如沸弄痹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)肛真。三九已至谐丢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚓让,已是汗流浹背乾忱。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留历极,地道東北人窄瘟。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像趟卸,于是被迫代替她去往敵國(guó)和親蹄葱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容