[C#] Lucene.net - 模糊搜尋FuzzyQuery

2012-10-28


這一篇來簡單說一下關於還很有改進空間的 FuzzyQuery ..
關於 Fuzzy :

概念是思維的基本形式之一,它反映了客觀事物的本質特征。人類在認識過程中,把感覺到的事物的共同特點抽象出來加以概括,這就形成了概念。比如從白雪、白馬、白紙等事物中抽象出“白”的概念。一個概念有它的內涵和外延,內涵是指該概念所反映的事物本質屬性的總和,也就是概念的內容。外延是指一個概念所確指的對象的範圍。例如“人”這個概念的內涵是指能製造工具,並使用工具進行勞動的動物,外延是指古今中外一切的人。
來源 : http://wiki.mbalib.com/zh-tw/%E6%A8%A1%E7%B3%8A%E7%90%86%E8%AE%BA
這也是 Lucene.net 所內建的不過他通常使用在英文文字上面
網路上面常見的範例 就是 搜尋 fuzzy 但是當您打錯字的時候 打成 wuzza 他可以可以搜尋得到
他可以在某種程度範圍上面容錯..
上篇文章說過關於盤古的作用一段文字他在也不是看成一個一個中文字視為一個 Term 而是將他分析過後的分詞看成一個 Term
建立 Index :
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();

//Index 存放路徑

string indexPath = AppDomain.CurrentDomain.BaseDirectory + "\\Index1\\";



FSDirectory dir = FSDirectory.Open(new DirectoryInfo(indexPath));

//IndexWriter



// 使用盤古分詞

var analyzer = new Lucene.Net.Analysis.PanGu.PanGuAnalyzer();



IndexWriter indexWriter = new IndexWriter(dir, analyzer, IndexWriter.MaxFieldLength.UNLIMITED);



indexWriter.DeleteAll();





// 還原且加入需做 index 的欄位

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_Age = new Field("Age", ds["Age"].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);

    Field f_BirthDay = new Field("BirthDay", DateTime.Parse(ds["Birthday"].ToString()).ToString("yyyyMMdd"), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO);

    doc.Add(f_Id); doc.Add(f_Age); doc.Add(f_Memo); doc.Add(f_BirthDay);

    indexWriter.AddDocument(doc);

}

indexWriter.Optimize();

indexWriter.Commit();

indexWriter.Close();

sw.Stop();

Response.Write("建立" + allObjects.Length + "筆索引花費時間: " + sw.Elapsed + "");

這時候後我們使用 FuzzyQuery

Query query =new FuzzyQuery(new Term("Memo","查詢文字"),0.1F);

完整 C#  Code :


// 啟用監看

Stopwatch sw = new Stopwatch();

sw.Start();



// 讀取索引

string indexPath = AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\Index1\\";

DirectoryInfo dirInfo = new DirectoryInfo(indexPath);

FSDirectory dir = FSDirectory.Open(dirInfo);

IndexSearcher search = new IndexSearcher(dir, true);

// 針對 Memo 欄位進行搜尋

QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, "Memo", new PanGuAnalyzer());

// 搜尋的關鍵字

Query query =new FuzzyQuery(new Term("Memo",txtKeyword.Text),0.1F);

// 開始搜尋

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)

{

    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 />");

}

關於最小相似度跟評分機制 這一塊我叫比較鮮少研究 可以參考這一篇 這一篇說的很細: http://grantbb.iteye.com/blog/181802

來看一下測試結果:

2012-10-04_134651

2012-10-04_134703



2012-10-04_134732


當麻許的超技八 2014 | Donma Hsu Design.