摘要:Lucene.Net 使用 Snowball
Lucene.Net 有一個 Contrib Library , Snowball ,
若要取得 Library 可到 下列網址下載
https://www.nuget.org/packages/Lucene.Net.Contrib/3.0.3
它提供詞幹還原的功能 , 就像 organization 會被還原成 organ
Sample :
我們將插入一索引名為 text , 值為 walking , 無論我們搜尋 walk , walked
或者 walking , 其搜尋結果都是我們插入的索引值 , walking
Step 1 : Build Index
private void BuildIndex()
{
DirectoryInfo dirInfo = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\App_Data");
FSDirectory dir = FSDirectory.Open(dirInfo);
IndexWriter iw = new IndexWriter(dir, new SnowballAnalyzer(Version.LUCENE_30, "English"), true, IndexWriter.MaxFieldLength.UNLIMITED);
Document doc = new Document();
Field field = new Field("text", "walking", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO);
doc.Add(field);
iw.AddDocument(doc);
iw.Optimize();
iw.Commit();
iw.Close();
}
Step 2 : Search
public void Search(string KeyWord)
{
DirectoryInfo dirInfo = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\App_Data");
FSDirectory dir = FSDirectory.Open(dirInfo);
IndexSearcher search = new IndexSearcher(dir, true);
QueryParser parser = new QueryParser(Version.LUCENE_30, "text", new SnowballAnalyzer(Version.LUCENE_30, "English"));
Query query = parser.Parse(KeyWord);
var hits = search.Search(query, null, search.MaxDoc).ScoreDocs;
foreach (var res in hits)
{
Response.Write(string.Format("text:{0}"
, search.Doc(res.Doc).Get("text").ToString() + "
"));
}
}
Result :
text:walking
當我們使用 SnowBall Analyzer 建立 Index 時 , 它會將我們輸入的單字 walking 詞幹還原成 walk ,
然後將它存進 Index , 如下圖 , 我們使用 Luke.Net 來觀察 Index
這時候我們在 Search 時 , 也需要使用 Snowball Analyzer , 如果我們搜尋字串 walking ,
它也會將它還原成 walk , 這樣子就直接產生我們在上述的結果了
另外關於 Snowball 的建構式中 , 第二個參數 name , 其 Api 解釋為
Builds the named analyzer with no stop words
若是你輸入了 english 或者空字串 , 他都會產生錯誤 ,
其原因是 , 你必須輸入他所支援的國家名稱 , 因為他會透過 name 參數呼叫相對應的 語言詞幹還原 class ,
也就是當你輸入 English , 他就會去呼叫 EnglishStemmer
我們可以透過 ILSpy 來觀察
Step 1 :
Snowball 繼承了 Lucene.Net.Analysis.Analyzer Class , 而在這裡他 override 了 base 的 TokenStream ,
我們可以看到它回傳了 SnowballFilter instance
public override TokenStream TokenStream(string fieldName, TextReader reader)
{
TokenStream result = new StandardTokenizer(this.matchVersion, reader);
result = new StandardFilter(result);
result = new LowerCaseFilter(result);
if (this.stopSet != null)
{
result = new StopFilter(StopFilter.GetEnablePositionIncrementsVersionDefault(this.matchVersion), result, this.stopSet);
}
return new SnowballFilter(result, this.name);
}
Step 2 :
我們可以看到它會在這裡藉由取得 name 參數組成 class 名稱 , 然後藉由反射去取得 class instance
public SnowballFilter(TokenStream input, string name) : base(input)
{
try
{
Type stemClass = Type.GetType("SF.Snowball.Ext." + name + "Stemmer");
this.stemmer = (SnowballProgram)Activator.CreateInstance(stemClass);
}
catch (Exception e)
{
throw new SystemException(e.ToString());
}
this.termAtt = this.AddAttribute();
}
Step 3 : 接下來我們來看看有那些語言的詞幹還原可以使用
還滿多的