Lucene 使用
這幾天無聊,看了一下Lucene。使用如下:
1.下載Lucene,可以下載下來Lucene.net源碼。
2.建立一個Templucene工程中,並且在工程中添加lucene工程,或則是lucene引用。我的介面是這樣的。
3.建立目錄在debug下建立IndexDirectory,並且在這裡文件下建立2個文件夾,一個放要查詢的文檔temp,一個放生成的索引文件index。
4.建立處理類LuceneFunction,代碼如下:
public class LuceneFunction { private const string FILE_KEY_NAME = "filename";//文件名 private const string CONTENT_KEY_NAME = "contents";//內容 private const string CREATEDATE = "createDate"; private const string TITLE = "title";//標題 /// <summary> /// 目錄建立索引 /// </summary> /// <param name="writer"></param> /// <param name="file"></param> public static void IndexDirectory(IndexWriter writer, io.FileInfo file) { if (io.Directory.Exists(file.FullName)) { String[] files = io.Directory.GetFileSystemEntries(file.FullName); // an IO error could occur if (files != null) { for (int i = 0; i < files.Length; i++) { IndexDirectory(writer, new io.FileInfo(files[i])); //这里是一个递归 } } } else { //IndexFile(file, writer); AddHtmlDocument(file.FullName, writer); } } /// <summary> /// 單一個文件建立索引 /// </summary> /// <param name="file"></param> /// <param name="writer"></param> private static void IndexFile(io.FileInfo file, IndexWriter writer) { Console.Out.WriteLine("adding " + file); try { Document doc = new Document(); doc.Add(new Field(FILE_KEY_NAME, file.FullName, Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field(CONTENT_KEY_NAME, new io.StreamReader(file.FullName).ReadToEnd(), Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field(CREATEDATE,new io.FileInfo( file.FullName).LastWriteTime.ToString(), Field.Store.YES, Field.Index.ANALYZED)); //doc.Add(new Field(CONTENT_KEY_NAME, new io.StreamReader(file.FullName),Field.TermVector.WITH_OFFSETS)); writer.AddDocument(doc); } catch (io.FileNotFoundException fnfe) { } } public static void CreateIndex(string directory) { IndexWriter writer = new IndexWriter( new MMapDirectory( new System.IO.DirectoryInfo(@"IndexDirectory\index")) , new ChineseAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED); IndexDirectory(writer, new System.IO.FileInfo(directory)); writer.Optimize(); writer.Dispose(); } public static void SearchIndex(string queryString) { IndexSearcher indexSearcher = new IndexSearcher(new MMapDirectory( new System.IO.DirectoryInfo(@"IndexDirectory\index"))); MultiFieldQueryParser QueryParser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, new string[] { CONTENT_KEY_NAME, FILE_KEY_NAME }, new ChineseAnalyzer()); //QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, CONTENT_KEY_NAME, analyzer); Query query = QueryParser.Parse(queryString); TopDocs docs = indexSearcher.Search(query,null,1000); for (int i = 0; i < docs.TotalHits; i++) { Document doc = indexSearcher.Doc(docs.ScoreDocs[i].Doc);//得到文檔的內容 //Console.WriteLine(string.Format("文件名:{0} 內容:{1} 創建時間{2}", doc.Get(FILE_KEY_NAME), // doc.Get(CONTENT_KEY_NAME), doc.Get(CREATEDATE))); Console.WriteLine(string.Format("文件名:{0}", doc.Get(FILE_KEY_NAME))); } } public static void AddHtmlDocument(string path, IndexWriter writer) { string exname = io.Path.GetExtension(path); Document doc = new Document(); string html; if (exname.ToLower() == ".html" || exname.ToLower() == ".htm" || exname.ToLower() == ".txt") { using (io.StreamReader sr = new io.StreamReader(path, System.Text.Encoding.Default)) { html = sr.ReadToEnd(); } } else { using (io.StreamReader sr = new io.StreamReader(path, System.Text.Encoding.Unicode)) { html = sr.ReadToEnd(); } } //int relativePathStartsAt = this.docRootDirectory.EndsWith("\\") ? this.docRootDirectory.Length : this.docRootDirectory.Length + 1; //string relativePath = path.Substring(relativePathStartsAt); //string title = io.Path.GetFileName(path); //判断若是网页则去标签否则不用 if (exname.ToLower() == ".html" || exname.ToLower() == ".htm") { doc.Add(new Field(CONTENT_KEY_NAME, parseHtml(html), Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field(TITLE, getTitle(html), Field.Store.YES, Field.Index.ANALYZED)); } else { doc.Add(new Field(CONTENT_KEY_NAME, html, Field.Store.YES, Field.Index.ANALYZED)); } doc.Add(new Field(FILE_KEY_NAME, path, Field.Store.YES, Field.Index.NO)); doc.Add(new Field(CREATEDATE, new io.FileInfo(path).LastWriteTime.ToString(), Field.Store.YES, Field.Index.ANALYZED)); writer.AddDocument(doc); } /**/ /// <summary> /// 去除网页中的标签 /// </summary> /// <param name="html">网页</param> /// <returns>返回去除后的网页文本</returns> private static string parseHtml(string html) { string temp = Regex.Replace(html, "<[^>]*>", ""); return temp.Replace(" ", " "); } /**/ /// <summary> /// 获取网页标题 /// </summary> /// <param name="html"></param> /// <returns></returns> private static string getTitle(string html) { Match m = Regex.Match(html, "<title>(.*)</title>"); if (m.Groups.Count == 2) return m.Groups[1].Value; return "文档标题未知"; } }
5.使用:把要查詢的文檔放到temp下面。
代碼調用 :
LuceneFunction.CreateIndex(@"IndexDirectory\temp"); LuceneFunction.SearchIndex("Silverlight使用");
第一步創建索引,第二部查詢。
6.對於一些使用對象的說明:
61.初始化索引對象:
IndexWriter writer = new IndexWriter( new MMapDirectory( new System.IO.DirectoryInfo(@"IndexDirectory\index")) , new ChineseAnalyzer(), true, IndexWriter.MaxFieldLength.LIMITED);
第一個參數是目錄,即要對哪個目錄進行索引。ChineseAnalyzer是分詞類,這個使用的是中文分詞。
6.2建立索引對象后,給這個對象添加索引文件
Document doc = new Document(); doc.Add(new Field(FILE_KEY_NAME, file.FullName, Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field(CONTENT_KEY_NAME, new io.StreamReader(file.FullName).ReadToEnd(), Field.Store.YES, Field.Index.ANALYZED)); doc.Add(new Field(CREATEDATE,new io.FileInfo( file.FullName).LastWriteTime.ToString(), Field.Store.YES, Field.Index.ANALYZED)); //doc.Add(new Field(CONTENT_KEY_NAME, new io.StreamReader(file.FullName),Field.TermVector.WITH_OFFSETS)); writer.AddDocument(doc);
Document對象,相當於數據庫中的一條記錄。
就是把Document對象寫到索引中。
doc.Add(new Field(FILE_KEY_NAME, file.FullName, Field.Store.YES, Field.Index.ANALYZED));
是相當于給這個記錄的一個字段賦值。這裡是放文件名,作為key。
doc.Add(new Field(CONTENT_KEY_NAME, new io.StreamReader(file.FullName).ReadToEnd(), Field.Store.YES, Field.Index.ANALYZED));
是對文檔內容,加入到另一個字段,建立索引。
6.3 完成上面2部,那麼會在index目錄下會由文件生成,這樣這個文件的索引建立。已經為查詢做好準備了。
6.4 建立查詢對象
IndexSearcher indexSearcher = new IndexSearcher(new MMapDirectory(
new System.IO.DirectoryInfo(@"IndexDirectory\index")));
其中目錄指向,剛才生成索引的位置。
MultiFieldQueryParser QueryParser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, new string[] { CONTENT_KEY_NAME, FILE_KEY_NAME }, new ChineseAnalyzer());
指定要查詢的欄位。並且用中文分詞。
Query query = QueryParser.Parse(queryString);
生成查詢條件。
TopDocs docs = indexSearcher.Search(query,null,1000); for (int i = 0; i < docs.TotalHits; i++) { Document doc = indexSearcher.Doc(docs.ScoreDocs[i].Doc);//得到文檔的內容 //Console.WriteLine(string.Format("文件名:{0} 內容:{1} 創建時間{2}", doc.Get(FILE_KEY_NAME), // doc.Get(CONTENT_KEY_NAME), doc.Get(CREATEDATE))); Console.WriteLine(string.Format("文件名:{0}", doc.Get(FILE_KEY_NAME))); }
開始查詢。並且得到結果 。docs,對應這個查詢,只是查詢出索引,並沒有實際記載內容。
Document doc = indexSearcher.Doc(docs.ScoreDocs[i].Doc);
這一句,才把要的結果查詢出來了。放到Documen中,這個Documen和最上面寫入索引用的是一樣的。Documen就是查詢得到的內容。
doc.Get(FILE_KEY_NAME)是得到Document中相應欄位的數值。
7.對應html文件,可以對原有文件如果查到內容,會對相應內容,進行變色。這個就不做解釋了。
8.對於所有的文檔,只要能轉換成txt文件就都可以查詢了了。如果txt html doc pdf等。