使用Lucene.net創建索引,實現搜索的C#代碼示例
using System; using System.Collections.Generic; using System.Web.Mvc; using Lucene.Net.Store; using Lucene.Net.Analysis; using Lucene.Net.Analysis.Standard; using Lucene.Net.Index; using Lucene.Net.Documents; using Lucene.Net.Search; using Lucene.Net.QueryParsers; using System.Diagnostics; namespace LuceneNet.Web.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewBag.Message = "歡迎使用 ASP.NET MVC!"; return View(); } public ActionResult About() { return View(); } /// <summary> /// 添加索引 /// </summary> /// <returns></returns> public ActionResult AddIndex() { //為索引存儲目錄 string INDEX_STORE_PATH = Server.MapPath("~/SearchIndex"); #if DEBUG ///如果存在文件則刪除(測試用) if (System.IO.Directory.Exists(INDEX_STORE_PATH)) { System.IO.Directory.Delete(INDEX_STORE_PATH, true); } #endif Directory indexDirectory = FSDirectory.Open(new System.IO.DirectoryInfo(INDEX_STORE_PATH)); Analyzer analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29); IndexWriter writer = null; try { //檢查索引文件是否存在 bool iscreate = !Lucene.Net.Index.IndexReader.IndexExists(indexDirectory); //如果索引文件不存在則創建索引文件,否則創建索引文件 writer = new IndexWriter(indexDirectory, analyzer, iscreate, IndexWriter.MaxFieldLength.UNLIMITED); //開始添加索引 foreach (var item in Get()) { Document doc = new Document(); doc.Add(new Field("id", item.Id, Field.Store.YES, Field.Index.ANALYZED));//存儲,不分詞索引 doc.Add(new Field("classid", item.ClassId, Field.Store.YES, Field.Index.NOT_ANALYZED));//存儲,不分詞索引 doc.Add(new Field("classname", item.ClassName, Field.Store.YES, Field.Index.ANALYZED));//存儲,不分詞索引 doc.Add(new Field("title", item.Title, Field.Store.YES, Field.Index.ANALYZED));//存儲,分詞索引 doc.Add(new Field("summary", item.Summary, Field.Store.YES, Field.Index.ANALYZED));//存儲,分詞索引 doc.Add(new Field("createtime", item.CreateTime.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存儲,分詞索引 writer.AddDocument(doc); } writer.Optimize(); } catch (Exception) { throw; } finally { if (analyzer != null) analyzer.Close(); if (writer != null) writer.Close(); if (indexDirectory != null) indexDirectory.Close(); } return RedirectToAction("index"); } /// <summary> /// 搜索 /// </summary> /// <param name="k"></param> /// <param name="cid"></param> /// <returns></returns> public ActionResult Search(string k, string cid) { Stopwatch st = new Stopwatch(); st.Start();//計時開始 //為索引存儲目錄 string INDEX_STORE_PATH = Server.MapPath("~/SearchIndex"); var ver = Lucene.Net.Util.Version.LUCENE_29; Directory indexDirectory = FSDirectory.Open(new System.IO.DirectoryInfo(INDEX_STORE_PATH)); Analyzer analyzer = new StandardAnalyzer(ver); IndexSearcher searcher = null; List<Article> list; int recCount = 0; try { searcher = new IndexSearcher(indexDirectory, true); string[] fields = { "title", "summary" }; BooleanQuery booleanQuery = new BooleanQuery(); //多字段查詢同時搜索title和summary MultiFieldQueryParser parser = new MultiFieldQueryParser(ver, fields, analyzer); Query query = parser.Parse(k); //Query query1 = new QueryParser(ver, "classid", analyzer).Parse("1"); //TermQuery只能查詢不分詞的索引(Field.Index.NOT_ANALYZED) Query query1 = new TermQuery(new Term("id", "1")); //當classname為ANALYZED時搜不到 // Query query2 = new TermQuery(new Term("classname", "體育新聞")); //只有當classname為NOT_ANALYZED才可以搜得到, //由此得出TermQuery只能查詢不分詞的索引(Field.Index.NOT_ANALYZED)的結論 //但當id為ANALYZED時TermQuery卻可以收的到, //當搜classname中包含“體”時即Query query2 = new TermQuery(new Term("classname", "體")); //當搜classname中包含“育”時即Query query2 = new TermQuery(new Term("classname", "育")); //可以搜得到。因此,由此得出,TermQuery搜的是最小單位,由此又得出Lucene是把“體育新聞”拆分成了"體/育/新/聞"四部分 //聽說Lucene分詞是按空格分的,那么把“體育新聞”,改成“體育 新聞”后再重新生成索引是不是可以搜的到呢? //Query query2 = new TermQuery(new Term("classname", "體育")); //但是結果卻是搜不到,納悶...難道Lucene的分詞不是這么分而是更復雜? //StandardAnalyzer看來是對中文分詞不怎么好,當ClassName = "sports news"可以搜sports和news //StandardAnalyzer只支持英文的空格分詞 Query query2 = new TermQuery(new Term("classname", k)); //關于QueryParser的搜索當k為Empty或null時會報錯注意處理 //Query query3 = new QueryParser(ver, "title", analyzer).Parse(k); Query query3 = new QueryParser(ver, "title", analyzer).Parse(k); Query query4 = new PrefixQuery(new Term("classname", k)); Query query5 = new QueryParser(ver, "title", analyzer).Parse(k); TermRangeQuery query6 = new TermRangeQuery("createtime", "2012-1-3", "2012-5-3", true, true); //booleanQuery.Add(query1, BooleanClause.Occur.MUST); //booleanQuery.Add(query2, BooleanClause.Occur.MUST); //booleanQuery.Add(query3, BooleanClause.Occur.MUST); booleanQuery.Add(query4, BooleanClause.Occur.MUST); //booleanQuery.Add(query5, BooleanClause.Occur.MUST); booleanQuery.Add(query6, BooleanClause.Occur.MUST); TopDocs ts = searcher.Search(booleanQuery, null, 100);//執行搜索,獲取查詢結果集對象 recCount = ts.totalHits;//獲取命中的文檔個數 ScoreDoc[] hits = ts.scoreDocs;//獲取命中的文檔信息對象 st.Stop();//計時停止 ViewBag.EvenTime = string.Format("{0}毫秒,生成的Query語句:{1}", st.ElapsedMilliseconds, booleanQuery.ToString()); ViewBag.Count = recCount; list = new List<Article>(); foreach (var item in hits) { list.Add(new Article() { Id = searcher.Doc(item.doc).Get("id"), ClassId = searcher.Doc(item.doc).Get("classid"), ClassName = searcher.Doc(item.doc).Get("classname"), Title = searcher.Doc(item.doc).Get("title"), Summary = searcher.Doc(item.doc).Get("summary"), Score = item.score.ToString(), CreateTime = DateTime.Parse(searcher.Doc(item.doc).Get("createtime")) }); } } catch (Exception) { throw; } finally { if (searcher != null) { searcher.Close(); } } return View(list); } public List<Article> Get() { List<Article> list = new List<Article>(); list.Add(new Article() { Id = "1", ClassId = "1", ClassName = "體育新聞", Title = "微軟發布MVC4.0了", Summary = "微軟發布MVC4.0了,此版本更加強大", CreateTime = DateTime.Parse("2012-2-3") }); list.Add(new Article() { Id = "2", ClassId = "1", ClassName = "IT新聞", Title = "跟谷歌測試工程師的對話", Summary = "本文主人公Alan是谷歌的一名的軟件測試工程師,他的工作對象是谷歌的DoubleClick廣告管理系統(Bid Manager),這個系統提供讓廣告代理商和廣告客戶在多個廣告上進行報價競標的功能。", CreateTime = DateTime.Parse("2012-3-3") }); list.Add(new Article() { Id = "3", ClassId = "1", ClassName = "體育 新聞", Title = "好的程序員應該熟悉的幾門編程語言", Summary = "如果想成為一個好的程序員,甚至架構師、技術總監等,顯然只精通一種編程語言是不夠的,還應該在常見領域學會幾門編程語言,正如我們要成為高級人才不僅要會中文還要會英文", CreateTime = DateTime.Parse("2012-4-3") }); list.Add(new Article() { Id = "4", ClassId = "2", ClassName = "娛樂新聞", Title = "Javascript開發《三國志曹操傳》-開源講座(五)-可移動地圖的實現", Summary = "這一講的內容很簡單,大家理解起來會更快。因此我只對重點加以分析,其他的就輪到大家思考哦!首先來說,我對游戲開發可以算是不怎么深入,因為現在的程序員愛用canvas,我卻就只會拿幾個div湊和。", CreateTime = DateTime.Parse("2012-5-3") }); list.Add(new Article() { Id = "5", ClassId = "2", ClassName = "體育新聞", Title = "Android之BaseExpandableListAdapter使用心得", Summary = " 但是我最近做那個QQ項目是遇到一個問題,如果給這個ExpandableListView添加動態從網上獲取的數據呢?前面跟大家分享的時候,是用了靜態的數據,很好處理。", CreateTime = DateTime.Parse("2012-6-3") }); list.Add(new Article() { Id = "6", ClassId = "3", ClassName = "sports news", Title = "對話CSDN蔣濤:微軟移動互聯網馬太效應不可避免,小團隊需學會利用平臺", Summary = "CSDN是全球最大的中文IT社區,也是雷鋒網最重要的合作伙伴之一,自1999年創辦至今,有著非常強大的業界影響力和號召力,其專注IT信息傳播、技術交流、教育培訓和專業技術人才服務,在2012年移動開發者大會即將舉辦之際,雷鋒網對CSDN的掌門人蔣濤做了一次專訪,一起探討移動互聯網的新技術浪潮和下一波發展趨勢。", CreateTime = DateTime.Parse("2012-7-3") }); list.Add(new Article() { Id = "7", ClassId = "3", ClassName = "體育新聞", Title = "基于MySQL的分布式事務控制方案", Summary = "基于MySQL的分布式事務控制方案", CreateTime = DateTime.Parse("2012-8-3") }); list.Add(new Article() { Id = "8", ClassId = "4", ClassName = "sports news", Title = "IOS和Android開發的一些個人感受", Summary = "最近公司的產品 Android版本第二版也算到了收尾,新加了幾個功能性模塊,我基本也就撿了幾個好玩的模塊做了下。", CreateTime = DateTime.Parse("2012-9-3") }); list.Add(new Article() { Id = "9", ClassId = "5", ClassName = "IT資訊", Title = "Google Code的簡單使用", Summary = "google code簡介:用于管理代碼的倉庫,反正我是這么理解的。就比我們在公司的時候也會有個用于存放公司代碼的主機一樣,google同樣給我們提供了這樣的一個host。這樣我們可以在不同電腦不同地方隨時的checkout,commit,同時分享我們的項目。", CreateTime = DateTime.Parse("2012-10-3") }); list.Add(new Article() { Id = "10", ClassId = "33", ClassName = "IT資訊", Title = "谷歌在印度推Gmail免費短信服務", Summary = "歌一直在努力橋接發展中國家功能手機SMS服務和Gmail之間的服務,這不,近日谷歌在印度推出“Gmail SMS”服務,這使得印度的Gmail用戶可以從Gmail的窗口發送信息到手機上并且接受聊天信息的回復,目前谷歌的這項服務已經得到印度的八大運營商的支持。", CreateTime = DateTime.Parse("2012-11-3") }); list.Add(new Article() { Id = "11", ClassId = "11", ClassName = "體育新聞", Title = "鮑爾默:微軟新時代 軟硬結合“贏”未來", Summary = "微軟CEO鮑爾默在年度公開信中表示,微軟在未來將緊密結合硬件和軟件。鮑爾默認為,這是微軟的一個新時代。“我們看到了前所未有的機會,我們對此很興奮,并且保持著樂觀的心態。”", CreateTime = DateTime.Parse("2012-12-3") }); return list; } } public class Article { public string Id { get; set; } public string ClassId { get; set; } public string ClassName { get; set; } public string Title { get; set; } public string Summary { get; set; } public string Score { get; set; } public DateTime CreateTime { get; set; } } }
這段例子代碼用的Lucene.Net2.9.2版本。現在最新版本是Lucene.Net3.0;Lucene.Net可以使用NuGet的安裝得到
對Lucene.Net還不怎么理解的朋友可以看下面的文章: http://www.cnblogs.com/birdshover/archive/2008/08/28/1279044.html
本文由用戶 wufflina 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!