Lucene.Net 建立基本的 Full-Text Search

摘要:Lucene.Net

Lucene.Net  3.03 版本 (在語法上與之前的版本有些微差異) , 筆者使用此版本

(1)在語法上與之前的版本有些微差異
(2)Runtime4.0

 

Lucene.Net 2.9.2.2

(1)Runtime2.0

 

開發環境 : Visual Studio 2010

 

Dll檔 : 可至http://lucenenet.apache.org/ 下載

 

Lucene.Net 是一套搜尋引擎的 Library , 最早是建立在 Java 的專案上 , 

 

而 Lucene.Net 是特別建立在 .Net 的 Runtime 上  . 

 

一般 Lucene.Net 常常被拿來跟 SQL Server 的 Full-Text Search 拿來比較 

 

Lucene 與 SQL Server FTS 比較 :

  Lucene SQL Server FTS
倒排索引 Yes Yes
支援中 , 英文分詞 需使用外部的 Library Yes
Index 自動更新 No Yes
能否儲存 Index 在記憶體 Yes No
能否在 Index 儲存資料 Yes No
使用方式 API SQL Server
停用詞,同義詞支援 Yes Yes
萬用字元支援 Yes No
     
     

 

(1) SQL Server 與 Lucene.Net 都採用 Inverted Index ( 倒排索引 ) 的方式建立索引

     有關 SQL Server 使用 Inverted Index 的敘述可觀看網址 , 在 Full-text Search Processing 的段落有提到

 

(2) SQL Server 在佈署上比 Lucene 容易許多 , 而 Lucene 有比較高的學習門檻

      例如有一堆 API 需要學習

 

有興趣的讀者可至下列網址參考兩種做法的差異 :

 Lucene.Net and SQL Server

SQL Server  and regular expressions

 

對於 SQL Server 與 Lucene 的差異在效果與效能的差異可以參考下列連結 : 

Comparing Microsoft SQL Server FTS and Apache Lucene

 

The following will demo :

我們將從一段內容中找到我們所需要的關鍵字 "holmes"

內容 : 但是holmes 是一個專業Programer

 

Step1 : Build Index :

 

 public void BuildIndex()
    {
        //從App_Data底下讀入Index檔案 , 若沒有會自動建立
        DirectoryInfo dirInfo = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\App_Data");
        FSDirectory dir = FSDirectory.Open(dirInfo);
        IndexWriter iw = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_30), true, IndexWriter.MaxFieldLength.UNLIMITED);

        //這裡將會寫進一份文件,而文件包含許多field(屬性),你可以決定這些屬性是否需要被索引
        Document doc = new Document();
        Field field = new Field("ID", "holmes2136", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO);
        Field field2 = new Field("DESC", "但是Holmes是專業PG", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO);

        doc.Add(field);
        doc.Add(field2);
        iw.AddDocument(doc);

        iw.Optimize();
        iw.Commit();

        //IndexWriter有實作IDisposable , 
        //表示握有外部資源,所以記的得Close
        iw.Close();

    }

 

我們可以看到在建立 Field Instance 時 , 需丟入五個參數 , 依序為 :

一. 欄位名稱

二. 欄位 value

三. 是否儲存    是否要儲存資料於索引中 , 較適合儲存小量的資料來源

  1. Field.Store.Yes
  2. Field.Store.No

四. 是否索引    該資料來源的資料是否要在使用者搜尋時被檢索

  1. NO           表示該 Field 不需要索引 , 也就是使用者不需要去尋找該 Field 的值 
  2. ANALYZED   表示該 Field 先分詞在索引
  3. NOT_ANALYZED   表示不對該 Field 進行分詞 , 但是要對它進行索引 , 也就是該 Field 會被使用者尋找
  4. NOT_ANALYZED_NO_NORMS   表示對該 Field 進行索引 , 但是不使用 Analyzer , 同時禁止參與評分
  5. ANALYZED_NO_NORMS   表示對該 Field 進行索引 , 但是使用 Analyzer , 同時禁止參與評分

五. 是否分詞    資料來源的資料是否要經過分詞

 

 

Step2 : Search :

 

public void Search(string keyWord) {

        string indexPath = AppDomain.CurrentDomain.BaseDirectory.ToString() + "\\App_Data\\";
        DirectoryInfo dirInfo = new DirectoryInfo(indexPath);
        FSDirectory dir = FSDirectory.Open(dirInfo);
        IndexSearcher search = new IndexSearcher(dir, true);
        // 針對 DESC 欄位進行搜尋
        QueryParser parser = new QueryParser(Lucene.Net.Util.Version.LUCENE_30, "DESC", new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30));
        // 搜尋的關鍵字
        Query query = parser.Parse(keyWord);
        // 開始搜尋
        var hits = search.Search(query, null, search.MaxDoc).ScoreDocs;

        foreach (var res in hits)
        {
            Response.Write(string.Format("ID:{0} / DESC{1}",search.Doc(res.Doc).Get("ID").ToString()
                                        ,search.Doc(res.Doc).Get("DESC").ToString().Replace(keyWord, "" + keyWord + "") + "
"));
        }


    }

 

Step3 : Result

ID:holmes2136 / DESC但是Holmes是專業PG

 

 

何謂倒排索引 ( Inverted Index ) : 

 

當我們在閱讀一本書時 , 通常使用頁數來尋找相關內容 , 每一頁上具有一定數量的文字  , 

這些文字記錄了資訊 , 當使用倒排方式後 , 不再有整頁的資訊 , 資訊被切割成一個個的關鍵字 , 

並輔以關鍵字所在原書中的頁數 , 而構成一個倒排基本單位  ---- 開發專屬個人的引擎一書

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

參考來源 : 

Lucene.Java Wiki

CodeProject

Lucene.Net

Lucene Tutorial

開發專屬個人的搜尋引擎書籍