Lucene4Net以及盤古分詞


l 打開PanGu4Lucene\WebDemo\Bin,將Dictionaries添加到項目根路徑(改名為Dict),添加對PanGu.dll(同目錄下不要有Pangu.xml,那個默認的配置文件的選項對於分詞結果有很多無用信息)、PanGu.Lucene.Analyzer.dll的引用

l 把上節代碼的AnalyzerPanGuAnalyzer代替

l 運行報錯?通用技巧:把Dict目錄下的文件“復制到輸出目錄”設定為“如果較新則復制”。

對以下引用進行添加:

使用代碼示例:

Analyzer analyzer = new PanGuAnalyzer();
            //Analyzer analyzer = new StandardAnalyzer();//new后面的類為分詞的方法
            TokenStream tokenStream = analyzer.TokenStream("", new System.IO.StringReader(TextBox1.Text));
            Lucene.Net.Analysis.Token token = null;
            while ((token = tokenStream.Next()) != null)
            {
                //Console.WriteLine(token.TermText());
                Response.Write(token.TermText()+"<br/>");
            }

Lucene.Net核心類簡介

l Directory表示索引文件(Lucene.net用來保存用戶扔過來的數據的地方)保存的地方,是抽象類,兩個子類FSDirectory(文件中)、RAMDirectory (內存中)。使用的時候別和IO里的Directory弄混了。

l 創建FSDirectory的方法,FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath),new NativeFSLockFactory()), path索引的文件夾路徑

l IndexReader對索引進行讀取的類,對IndexWriter進行寫的類。

l IndexReader的靜態方法bool IndexExists(Directory directory)判斷目錄directory是否是一個索引目錄。IndexWriterbool IsLocked(Directory directory) 判斷目錄是否鎖定,在對目錄寫之前會先把目錄鎖定。兩個IndexWriter沒法同時寫一個索引文件。IndexWriter在進行寫操作的時候會自動加鎖,close的時候會自動解鎖。IndexWriter.Unlock方法手動解鎖(比如還沒來得及close IndexWriter 程序就崩潰了,可能造成一直被鎖定)。

 

 

創建索引:

l 構造函數:IndexWriter(Directory dir, Analyzer a, bool create, MaxFieldLength mfl)因為IndexWriter把輸入寫入索引的時候,Lucene.net是把寫入的文件用指定的分詞器將文章分詞(這樣檢索的時候才能查的快),然后將詞放入索引文件。

l void AddDocument(Document doc),向索引中添加文檔(Insert)。Document類代表要索引的文檔(文章),最重要的方法Add(Field field),向文檔中添加字段。Document是一片文檔,Field是字段(屬性)。Document相當於一條記錄,Field相當於字段。

l Field類的構造函數 Field(string name, string value, Field.Store store, Field.Index index, Field.TermVector termVector)

l  name表示字段名; value表示字段值;

l store表示是否存儲value值,可選值 Field.Store.YES存儲, Field.Store.NO不存儲, Field.Store.COMPRESS壓縮存儲;默認只保存分詞以后的一堆詞,而不保存分詞之前的內容,搜索的時候無法根據分詞后的東西還原原文,因此如果要顯示原文(比如文章正文)則需要設置存儲。

l  index表示如何創建索引,可選值Field.Index. NOT_ANALYZED

l ,不創建索引,Field.Index. ANALYZED,創建索引;創建索引的字段才可以比較好的檢索。是否碎屍萬段!是否需要按照這個字段進行“全文檢索”。

l termVector表示如何保存索引詞之間的距離。“北京歡迎你們大家”,索引中是如何保存“北京”和“大家”之間“隔多少單詞”。方便只檢索在一定距離之內的詞。

l 為什么要把帖子的url做為一個Field,因為要在搜索展示的時候先帖子地址取出來構建超鏈接,所以Field.Store.YES;一般不需要對url進行檢索,所以Field.Index.NOT_ANALYZED

l 案例:對10001100號帖子進行索引。“只要能看懂例子和文檔,稍作修改即可實現自己的需求

1、對數據進行索引

string indexPath = "c:/temp";
FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath),new NativeFSLockFactory());
bool isUpdate = IndexReader.IndexExists(directory);
            if (isUpdate)
            {
                //如果索引目錄被鎖定(比如索引過程中程序異常退出),則首先解鎖
            if (IndexWriter.IsLocked(directory))
                {
                  IndexWriter.Unlock(directory);
                }
        }
 IndexWriter writer = new IndexWriter(directory, new PanGuAnalyzer(), !isUpdate, Lucene.Net.Index.IndexWriter.MaxFieldLength.UNLIMITED);
            for (int i = 1000; i < 1100; i++)
            {
                string txt = File.ReadAllText(@"C:\MxDownload\dnt_3.1.0_sqlserver\upload_files\文章\" + i + ".txt");
                Document document = new Document();
                document.Add(new Field("number", i.ToString(), Field.Store.YES, Field.Index. NOT_ANALYZED));
                document.Add(new Field("body", txt, Field.Store.YES, Field.Index. ANALYZED, Lucene.Net.Documents.Field.TermVector.WITH_POSITIONS_OFFSETS));
                writer.AddDocument(document);
                Console.WriteLine("索引"+i+"完畢");
            }
            writer.Close();
            directory.Close();//不要忘了Close,否則索引結果搜不到

搜索:

l IndexSearcher是進行搜索的類,構造函數傳遞一個IndexReaderIndexSearchervoid Search(Query query, Filter filter, Collector results)方法用來搜索,Query是查詢條件, filter目前傳遞null, results是檢索結果,TopScoreDocCollector.create(1000, true)方法創建一個Collector1000表示最多結果條數,Collector就是一個結果收集器。

l Query有很多子類,PhraseQuery是一個子類。 PhraseQuery用來進行多個關鍵詞的檢索,調用Add方法添加關鍵詞,query.Add(new Term("字段名", 關鍵詞))PhraseQuery. SetSlop(int slop)用來設置關鍵詞之間的最大距離,默認是0,設置了Slop以后哪怕文檔中兩個關鍵詞之間沒有緊挨着也能找到。

• query.Add(new Term("字段名", 關鍵詞))

• query.Add(new Term("字段名", 關鍵詞2))

• 類似於:where 字段名 contains 關鍵詞 and 字段名 contais 關鍵詞2

l 調用TopScoreDocCollectorGetTotalHits()方法得到搜索結果條數,調用HitsTopDocs TopDocs(int start, int howMany)得到一個范圍內的結果(分頁),TopDocsscoreDocs字段是結果ScoreDoc數組, ScoreDoc doc字段為Lucene.Net為文檔分配的id(為降低內存占用,只先返回文檔id),根據這個id調用searcherDoc方法就能拿到Document了(放進去的是Document,取出來的也是Document);調用doc.Get("字段名")可以得到文檔指定字段的值,注意只有Store.YES的字段才能得到,因為Store.NO的沒有保存全部內容,只保存了分割后的詞。

l 編寫檢索功能,搜索“網站 志願者”。練習分詞,用戶不用空格。如果確定用盤古分詞,那么用盤古的Segment類更方便。

l 檢索不出來的可能的原因:路徑問題,分詞是否正確、盤古分詞如果指定忽略大小寫,則需要統一按照小寫進行搜索

l Todo:第一個版本應該保存bodytitle,搜索結果形成超鏈接,不顯示正文。

搜索代碼:

string kw = Console.ReadLine();
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 kw.Split(' '))//先用空格,讓用戶去分詞,空格分隔的就是詞“計算機   專業”
            {
                query.Add(new Term("body", word));
            }
            query.SetSlop(100);
             TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);
                searcher.Search(query, null, collector);
         ScoreDoc[] docs = collector.TopDocs(0, collector.GetTotalHits()).scoreDocs;
 for (int i = 0; i < docs.Length; i++)
                {                    
                    int docId = docs[i].doc;
                    Document doc = searcher.Doc(docId);
                   Console.WriteLine(doc.Get("number"));
                Console.WriteLine(doc.Get("body"));
            }

網頁采集:

l 復習WebClient的用法,調用DownloadString方法下載頁面。抓取DiscuzNT!的9001000貼。亂碼怎么辦?亂碼的唯一原因“編碼不一致”。

l WebClient抓取到的是頁面的源代碼,如何得到頁面的標題、文字、超鏈接呢?

l 用mshtml進行html的解析,IE就是使用mshtml進行網頁解析的。添加對Microsoft.mshtml的引用(如果是VS2010,修改這個引用的“嵌入互操作類型”為False。(*“復制本地”設置為True“特定版本”設置為False,這樣在沒有安裝VS的機器中也可以用。)

•  HTMLDocumentClass doc = new HTMLDocumentClass();

• doc.designMode = "on"; //不讓解析引擎去嘗試運行javascript

• doc.IHTMLDocument2_write(要解析的代碼);

• doc.titledoc.body.innerText,更多用法自己探索。

• 所有Dom方法都能在mshtml中調用

搜索結果高亮顯示的方法:

l 高亮顯示,只顯示包含關鍵詞的部分。參考盤古分詞的文檔。

l 從網上、文檔找來的代碼不用細讀每行代碼,先把它拿過來運行通過再說。

l 不用每次改代碼都重啟,在項目的屬性頁面的Web中選中“啟用編輯並繼續(Enable Edit and Continue

高亮顯示的代碼:

private static String highLight(string keyword,String content) 
        {
            PanGu.HighLight.SimpleHTMLFormatter formatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color='red'>", "</font>");
            PanGu.HighLight.Highlighter highlighter = new PanGu.HighLight.Highlighter(formatter, new Segment());
            highlighter.FragmentSize = 500;
            string msg = highlighter.GetBestFragment(keyword,content);
if (string.IsNullOrEmpty(msg))
            {
                return content;
            }
            else
            {
                return msg;
            }
        }


 String hightlightTitle = highLight(keyword, title);
                    String hightlightBody = HttpUtility.HtmlEncode(body);//防止XSS攻擊
                    hightlightBody = highLight(keyword, hightlightBody);

 


免責聲明!

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



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