Lucene.Net+盤古分詞器(詳細介紹)(轉)


出處:http://www.cnblogs.com/magicchaiy/archive/2013/06/07/LuceneNet%E7%9B%98%E5%8F%A4%E5%88%86%E8%AF%8D%E5%99%A8%E5%AE%9E%E4%BE%8B%E5%88%86%E6%9E%90%E4%BB%8B%E7%BB%8D.html

 

本章閱讀概要

1、Lucenne.Net簡介

2、介紹盤古分詞器

3、Lucene.Net實例分析

4、結束語(Demo下載)

Lucene.Net簡介

  Lucene.net是Lucene的.net移植版本,是一個開源的全文檢索引擎開發包,即它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎。開發人員可以基於Lucene.net實現全文檢索的功能。   

  Lucene.net是Apache軟件基金會贊助的開源項目,基於Apache License協議。   

  Lucene.net並不是一個爬行搜索引擎,也不會自動地索引內容。我們得先將要索引的文檔中的文本抽取出來,然后再將其加到Lucene.net索引中。標准的步驟是先初始化一個Analyzer、打開一個IndexWriter、然后再將文檔一個接一個地加進去。一旦完成這些步驟,索引就可以在關閉前得到優化,同時所做的改變也會生效。這個過程可能比開發者習慣的方式更加手工化一些,但卻在數據的索引上給予你更多的靈活性。

(來自百度百科)

 

盤古分詞器

盤古分詞是一個中英文分詞組件。作者eaglet 曾經開發過KTDictSeg 中文分詞組件,擁有大量用戶。作者基於之前分詞組件的開發經驗,結合最新的開發技術重新編寫了盤古分詞組件。主要有以下功能:

1、中文未登陸詞識別

2、詞頻優先

3、一元分詞,多元分詞

4、中文人名分詞

5、繁體中文分詞

6、英文分詞

7、用戶自定義規則(字典管理,動態加載字典,關鍵詞高亮)

……

由於盤古分詞器不是本章的重點內容,就簡單帶過了。有興趣的朋友可以自己網上找找相關資料。文章末尾會提供一個盤古分詞器的應用程序供下載

 

Lucene.Net實例分析

先上一下Demo的圖把,看下最后運行效果:

 

數據是臨時隨便創建的數據,表格和樣式也是隨便畫的,不喜歡的朋友多包涵吶!

接下來就一步一步來講解整個編碼過程(主要對一些核心的類和細節作為講解過程),Let's GO

第一步:創建索引

1、由於索引是存放在硬盤里的,所以先定義一個索引的目錄

復制代碼
 1         /// <summary>
 2         /// 索引存放目錄
 3         /// </summary>
 4         protected string IndexDic
 5         {
 6             get
 7             {
 8                 return Server.MapPath("/IndexDic");
 9             }
10         }
復制代碼

2、創建索引器把要索引的內容寫入到指定目錄

1
IndexWriter writer =  new  IndexWriter(IndexDic, PanGuAnalyzer, isCreate, Lucene.Net.Index.IndexWriter.MaxFieldLength.LIMITED);

索引器的構造函數參數說明:

IndexDic是索引存放目錄

PanGuAnalyzer是盤古解析器(由於默認的解析器解析能力不強,所以替換為這個)

IsCreate是索引創建方式(true:重新新建索引,false:從舊的索引執行追加)

Lucene.Net.Index.IndexWriter.MaxFieldLength.LIMITED是文件長度是否限制

3、創建索引Document和往文檔寫入索引內容

復制代碼
 1         private void AddIndex(IndexWriter writer, string title, string content,string date)
 2         {
 3             try
 4             {
 5                 Document doc = new Document();
 6                 doc.Add(new Field("Title", title, Field.Store.YES, Field.Index.ANALYZED));//存儲且索引
 7                 doc.Add(new Field("Content", content, Field.Store.YES, Field.Index.ANALYZED));//存儲且索引
 8                 doc.Add(new Field("AddTime", date, Field.Store.YES, Field.Index.NOT_ANALYZED));//存儲且索引
 9                 writer.AddDocument(doc);
10             }
11             catch (FileNotFoundException fnfe)
12             {
13                 throw fnfe;
14             }
15             catch (Exception ex)
16             {
17                 throw ex;
18             }
19         }
復制代碼

Document是索引文檔,可以理解成數據庫里的記錄

Field是索引文檔里的字段,可以直接理解成數據庫里的字段

Field構造函數說明:

第一個是字段名稱(實例里是Title,Content,AddTime)。

第二個是字段的存儲方式(Field.Store.YES:進行存儲,Filed.Store.No:不進行存儲)有些字段值比較大,可以選擇No不存儲,對字段進行存儲是為了檢索的時候對某些字段進行提取。

第三個是是否索引(Field.Index.ANALYZED:索引, Field.Index.NOT_ANALYZED:非索引)

4、到此為止索引就創建完成了,應該可以看到索引目錄會產生幾個文件,如下圖:

第二步:搜索索引

lucene的搜索相當強大,它提供了很多輔助查詢類,每個類都繼承自Query類,各自完成一種特殊的查詢,你可以像搭積木一樣將它們任意組合使用,完成一些復雜操 作;另外lucene還提供了Sort類對結果進行排序,提供了Filter類對查詢條件進行限制。你或許會不自覺地拿它跟SQL語句進行比 較:“lucene能執行and、or、order by、where、like ‘%xx%’操作嗎?”回答是:“當然沒問題!”

復制代碼
 1         private void SearchIndex()
 2         {
 3             Dictionary<string, string> dic = new Dictionary<string, string>();
 4             BooleanQuery bQuery = new BooleanQuery();
 5             string title = string.Empty;
 6             string content = string.Empty;
 7             if (Request.Form["title"] != null && Request.Form["title"].ToString()!="")
 8             {
 9                 title =GetKeyWordsSplitBySpace( Request.Form["title"].ToString());
10                 QueryParser parse = new QueryParser("Title", PanGuAnalyzer);
11                 Query query = parse.Parse(title);
12                 parse.SetDefaultOperator(QueryParser.Operator.AND);
13                 bQuery.Add(query, BooleanClause.Occur.MUST);
14                 dic.Add("title",Request.Form["title"].ToString());
15                 txtTitle = Request.Form["title"].ToString();
16             }
17             if (Request.Form["content"] != null && Request.Form["content"].ToString() != "")
18             {
19                 content = GetKeyWordsSplitBySpace(Request.Form["content"].ToString());
20                 QueryParser parse = new QueryParser("Content", PanGuAnalyzer);
21                 Query query = parse.Parse(content);
22                 parse.SetDefaultOperator(QueryParser.Operator.AND);
23                 bQuery.Add(query, BooleanClause.Occur.MUST);
24                 dic.Add("content",Request.Form["content"].ToString());
25                 txtContent = Request.Form["content"].ToString();
26             }
27             if (bQuery != null && bQuery.GetClauses().Length>0)
28             {
29                 GetSearchResult(bQuery, dic);
30             }
31         }
復制代碼

這段代碼創建了一個索引查詢器,對title和content這兩個字段進行查詢。

1、介紹各種Query

TermQuery: 首先介紹最基本的查詢,如果你想執行一個這樣的查詢:在content字段中查詢包含‘劉備的document”,那么你可以用TermQuery:

1             Term t = new Term("content", "劉備");
2             Query query = new TermQuery(t);

BooleanQuery :如果你想這么查詢:在content字段中包含”劉備“並且在title字段包含”三國“的document”,那么你可以建立兩個TermQuery並把它們用BooleanQuery連接起來:

1             TermQuery termQuery1 = new TermQuery(new Term("content", "劉備"));
2             TermQuery termQuery2 = new TermQuery(new Term("title", "三國"));
3             BooleanQuery booleanQuery = new BooleanQuery();
4             booleanQuery.Add(termQuery1, BooleanClause.Occur.SHOULD);
5             booleanQuery.Add(termQuery2, BooleanClause.Occur.SHOULD);

WildcardQuery :如果你想對某單詞進行通配符查詢,你可以用WildcardQuery,通配符包括’?’匹配一個任意字符和’*’匹配零個或多個任意字符,例如你搜索’三國*’,你可能找到’三國演義’或者’三國志’:

1             Query query = new WildcardQuery(new Term("content", "三國*"));

PhraseQuery :你可能對中日關系比較感興趣,想查找‘中’和‘日’挨得比較近(5個字的距離內)的文章,超過這個距離的不予考慮,你可以:

1             PhraseQuery query = new PhraseQuery(); 
2             query.SetSlop(5); 
3             query.Add(new Term("content ", "中"));
4             query.Add(new Term("content", "日"));

那么它可能搜到“中日合作……”、“中方和日方……”,但是搜不到“中國某高層領導說日本欠扁”。

PrefixQuery :如果你想搜以‘中’開頭的詞語,你可以用PrefixQuery:

1             PrefixQuery query = new PrefixQuery(new Term("content ", "中"));

FuzzyQuery :FuzzyQuery用來搜索相似的term,使用Levenshtein算法。假設你想搜索跟‘wuzza’相似的詞語,你可以:

1             Query query = new FuzzyQuery(new Term("content", "wuzza"));

你可能得到‘fuzzy’和‘wuzzy’。

RangeQuery: 另一個常用的Query是RangeQuery,你也許想搜索時間域從20060101到20060130之間的document,你可以用RangeQuery:

1             RangeQuery query = new RangeQuery(new Term("time","20060101"), new Term("time","20060130"), true);

最后的true表示用閉合區間。

第三步:返回索引結果

上面介紹完各種查詢的Query,接下來看看LuceneNet返回的數據集如何處理,如何顯示高亮,上代碼:

復制代碼
 1 private void GetSearchResult(BooleanQuery bQuery,Dictionary<string,string> dicKeywords)
 2         {          
 3             IndexSearcher search = new IndexSearcher(IndexDic,true);
 4             Stopwatch stopwatch = Stopwatch.StartNew();
 5             //SortField構造函數第三個字段true為降序,false為升序
 6             Sort sort = new Sort(new SortField("AddTime", SortField.DOC, true));
 7             TopDocs docs = search.Search(bQuery, (Filter)null, PageSize * PageIndex, sort);
 8             stopwatch.Stop();
 9             if (docs != null && docs.totalHits > 0)
10             {
11                 lSearchTime = stopwatch.ElapsedMilliseconds;
12                 txtPageFoot = GetPageFoot(PageIndex, PageSize, docs.totalHits, "sabrosus");
13                 for (int i = 0; i < docs.totalHits; i++)
14                 {
15                     if (i >= (PageIndex - 1) * PageSize && i < PageIndex * PageSize)
16                     {
17                         Document doc = search.Doc(docs.scoreDocs[i].doc);
18                         Article model = new Article()
19                         {
20                             Title = doc.Get("Title").ToString(),
21                             Content = doc.Get("Content").ToString(),
22                             AddTime = doc.Get("AddTime").ToString()
23                         };
24                         list.Add(SetHighlighter(dicKeywords, model));
25                     }
26                 }
27             }
28         }
復制代碼

最后這段代碼相對比較簡單,我就說下幾個關鍵的類和高亮提示把。

1、關鍵類說明:

IndexSearcher:索引查詢器,它的構造函數有兩個參數,一個是索引文件路徑,一個是是否只讀(一般都設置為true就可以)。這個東西可以理解為SqlServer里面的查詢分析器。

Sort:看字眼可知道是索引排序類。主要說一下第三個參數,第三個參數是排序方式(true為降序,false為升序)。

TopDocs:這個是查詢后返回的文檔,可以理解為Sqlserver的表,search.Search可以當做是在查詢分析器里按了一次F5查詢。

2、設置關鍵字高亮:

復制代碼
 1         private Article SetHighlighter(Dictionary<string, string> dicKeywords, Article model)
 2         {
 3             SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"green\">", "</font>");
 4             Highlighter highlighter = new PanGu.HighLight.Highlighter(simpleHTMLFormatter, new Segment());
 5             highlighter.FragmentSize = 50;
 6             string strTitle = string.Empty;
 7             string strContent = string.Empty;
 8             dicKeywords.TryGetValue("title", out strTitle);
 9             dicKeywords.TryGetValue("content", out strContent);
10             if (!string.IsNullOrEmpty(strTitle))
11             {
12                 model.Title = highlighter.GetBestFragment(strTitle, model.Title);
13             }
14             if (!string.IsNullOrEmpty(strContent))
15             {
16                 model.Content = highlighter.GetBestFragment(strContent, model.Content);
17             }
18             return model;
19         }
復制代碼

這里用的也是盤古的高亮組件,設置高亮主要分兩個步驟:

設置高亮的顯示樣式、設置高亮的查詢關鍵字

SimpleHTMLFormatter:這個類是一個HTML的格式類,構造函數有兩個,一個是開始標簽,一個是結束標簽。

Segment:添加索引時並不是每個document都馬上添加到同一個索引文件,它們首先被寫入到不同的小文件,然后再合並成一個大索引文件,這里每個小文件都是一個segment。

結束語

感謝大家的閱讀,如果這篇文章能幫的上你,那是我的榮幸。如果文章哪里寫的不好,還請多多指教。

參考文獻:

http://www.cnblogs.com/jeffwongishandsome/archive/2011/01/02/1924107.html
http://space.itpub.net/12639172/viewspace-626546

Demo下載 (Demo是visual studio 2010編寫的,打不開請下載vs2010或者自己更改為vs2008或其他版本)

盤古分詞器下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM