標籤:Lucene blog http 使用 檔案 io for 2014
Lucene做站內搜尋的時候經常會遇到即時搜尋的應用情境,比如使用者搜尋的功能。實現即時搜尋,最普通的做法是,添加新的document之後,調用 IndexWriter 的 Commit 方法把記憶體中的索引提交到硬碟;然後重新開啟IndexReader,進行搜尋。但是索引一般儲存在硬碟上,而且當索引檔案比較大的時候,Commit操作和重新開啟IndexReader效率比較低。於是就想,可否一份索引的IndexWriter始終開啟,當需要添加或刪除Document時,直接調用該IndexWriter,從而實現增量索引;對於需要需要實現近即時搜尋的索引,可以通過IndexReader的IsCurrent方法判斷,如果有索引更新,則返回false,這時候需要調用IndexReader的Reopen()方法得到新的IndexReader對象,重新建立IndexSearcher對象即可。至於IndexWriter何時Commit,可以使用定時任務,半分鐘調用一次,也可以在意外情況下通過外部代碼調用。 近即時搜尋的實現實現近即時搜尋,需要保持IndexWriter開啟,在索引有了增加或刪除操作後,通過IndexReader的Reopen方法。需要注意的問題有:線程同步、IndexReader的引用計數。增量索引
/// <summary>/// 添加索引內容/// </summary>/// <param name="indexDocuments">待添加的索引文檔</param>/// <param name="reopen">是否重新開啟索引</param>public void Insert(IEnumerable<Document> indexDocuments, bool reopen = true){ lock (_lock) { if (indexDocuments == null || !indexDocuments.Any()) { return; } IndexWriter indexWriter = GetIndexWriter(); try { foreach (Document doc in indexDocuments) { indexWriter.AddDocument(doc); } } catch (Exception ex) { throw new ExceptionFacade(string.Format("An unexpected error occured while add documents to the index [{0}].", this.indexPath), ex); } if (reopen) { ReopenSearcher(); } }}
/// <summary>/// 刪除索引內容/// </summary>/// <param name="ids">索引內容對應的實體主鍵</param>/// <param name="fieldNameOfId">實體主鍵對應的索引欄位名稱</param>/// <param name="reopen">是否重新開啟NRT查詢</param>public void Delete(IEnumerable<string> ids, string fieldNameOfId, bool reopen = true){ lock (_lock) { if (ids == null && ids.Count() == 0) { return; } IndexWriter indexWriter = GetIndexWriter(); try { List<Term> terms = new List<Term>(); foreach (var id in ids) { Term term = new Term(fieldNameOfId, id); terms.Add(term); } indexWriter.DeleteDocuments(terms.ToArray()); } catch (Exception ex) { throw new ExceptionFacade(string.Format("An unexpected error occured while delete documents to the index [{0}].", this.indexPath), ex); } if (reopen) { ReopenSearcher(); } }}