2012-10-04

[C#] Lucene.net - 將索引從記憶體(RAMDirectory) 放回磁碟中

 

簡單解釋一下,有些常用的Index 可能我們會先做到記憶體中,一個時間我們在寫回硬碟…

製作索引的代價跟搜尋比較起來是非常高昂昂貴的…

所以這範例我們分成四個步驟..

1.建立索引到記憶體

2.搜尋記憶體中資料 (驗證是否建立索引至記憶體成功)

3.將記憶體中索引寫回磁碟

4.搜尋磁碟中索引(驗證是否磁碟中索引可被使用)

2012-10-04_133913

建立索引到記憶體

這邊可以參考此篇文章 :Lucene.net–使用RAMDirectory、 優化Index

所以就不贅述:

C# Code :

private static RAMDirectory _mDirectory = new RAMDirectory();
 protected void Button1_Click(object sender, EventArgs e)
 {
     Stopwatch sw = new Stopwatch();
     // 讀取所有資料
     var di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "\\Source\\");
     sw.Start();
     //將物件都還原
     var allObjects = di.GetFiles().Select(
         x => JObject.Parse((File.ReadAllText(x.FullName)))).ToArray();
     //IndexWriter 將資料寫入 mDirectory
     IndexWriter indexWriter = new IndexWriter(_mDirectory, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), true, IndexWriter.MaxFieldLength.UNLIMITED);
     foreach (JObject ds in allObjects)
     {
         Document doc = new Document();
         // 把每一個欄位都建立索引
         Field f_Id = new Field("Id", ds["Id"].ToString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO);
         Field f_Memo = new Field("Memo", ds["Memo"].ToString(), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO);
         doc.Add(f_Id); doc.Add(f_Memo);
         indexWriter.AddDocument(doc);
     }
     indexWriter.Optimize();
     indexWriter.Commit();
     indexWriter.Close();
     sw.Stop();
     Response.Write("花費時間: " + sw.Elapsed + "");
 }

 


2012-10-04_133924


備註:目標資料約莫1200 筆


搜尋記憶體中資料 (驗證是否建立索引至記憶體成功)


這時候我們透過搜尋對記憶體的搜尋結果


C# code:



// 啟用監看
Stopwatch sw = new Stopwatch();
sw.Start();
IndexSearcher search = new IndexSearcher(_mDirectory, true);
// 針對 Memo 欄位進行搜尋
QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "Memo", new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));
// 搜尋的關鍵字
Query query = parser.Parse(txtKeyword.Text);
// 開始搜尋
var hits = search.Search(query, null, search.MaxDoc()).ScoreDocs;
sw.Stop();
Response.Write("花費時間:" + sw.Elapsed + "<br /><hr />");
Response.Write("資料筆數:" + hits.Length + "<br /><hr />");
Response.Write("Result:<br />");
foreach (var res in hits)
{
    // 支援 Lucene.net 3.0 的做法
    Response.Write("Id:" + search.Doc(res.doc).Get("Id") + "  Memo=" + search.Doc(res.doc).Get("Memo").ToString().Replace(txtKeyword.Text, "<span style='color:red'>" + txtKeyword.Text + "</span>") + "<br />");
}

2012-10-04_133943


將記憶體中索引寫回磁碟


我的程式碼中 我先將原本索引的檔案夾砍掉 重新建立目的是 確保所有的索引都被我砍光 並且重新建立


C# code:



//來源的兩個index路徑
var dirInfo = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "\\Index\\");
//清除現有索引
dirInfo.Delete(true);
dirInfo.Create();
var diskDir = FSDirectory.Open(dirInfo);
RAMDirectory.Copy(_mDirectory, diskDir, false);

其實很簡單的觀念 我直接呼叫 _mDirectory.Copy 即可複製到我要指定的磁碟 至於第二個參數 是決定要不要將記憶體釋放 我在範例中並未釋放以方便搜尋


搜尋磁碟中索引(驗證是否磁碟中索引可被使用)


這邊就跟以前一樣了


C# Code :



// 啟用監看
Stopwatch sw = new Stopwatch();
sw.Start();
FSDirectory diskDir = FSDirectory.Open(new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "\\Index\\"));
IndexSearcher search = new IndexSearcher(diskDir, true);
// 針對 Memo 欄位進行搜尋
QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "Memo", new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));
// 搜尋的關鍵字
Query query = parser.Parse(txtKeyword.Text);
// 開始搜尋
var hits = search.Search(query, null, search.MaxDoc()).ScoreDocs;
sw.Stop();
Response.Write("花費時間:" + sw.Elapsed + "<br /><hr />");
Response.Write("資料筆數:" + hits.Length + "<br /><hr />");
Response.Write("Result:<br />");
foreach (var res in hits)
{
    // 支援 Lucene.net 3.0 的做法
    Response.Write("Id:" + search.Doc(res.doc).Get("Id") + "  Memo=" + search.Doc(res.doc).Get("Memo").ToString().Replace(txtKeyword.Text, "<span style='color:red'>" + txtKeyword.Text + "</span>") + "<br />");
}

2012-10-04_134000