2012-07-08 444 views
3

我的問題很簡單,當用IndexReader.openIfChanged (reader)替換以前的reader時,如何安全關閉oldReader如何安全關閉IndexReader?

下面是代碼:(利用Lucene 3.5)

IndexReader newReader=IndexReader.openIfChanged(reader); 
if(newReader!=null){ 
    IndexReader oldReader=reader; 
    IndexSearcher oldSearcher=searcher; 

    reader=newReader; 
    searcher=new IndexSearcher(newReader); 

    oldSearcher.close(); 
    oldReader.close();//or oldReader.decRef(),result is the same 
} 

這段代碼在一個後臺程序線程,每5秒運行時間

IndexReader實例(reader對象)是全球唯一

由於這種變化,我得到一個例外:

org.apache.lucene.store.AlreadyClosedException: this IndexReader is closed 
    at org.apache.lucene.index.IndexReader.ensureOpen(IndexReader.java:297) 
    at org.apache.lucene.index.IndexReader.getSequentialSubReaders(IndexReader.java:1622) 
    at org.apache.lucene.search.TermQuery$TermWeight.scorer(TermQuery.java:98) 
    at org.apache.lucene.search.BooleanQuery$BooleanWeight.scorer(BooleanQuery.java:298) 
    at org.apache.lucene.search.BooleanQuery$BooleanWeight.scorer(BooleanQuery.java:298) 
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:577) 
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:517) 
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:487) 
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:400) 
    at org.zenofo.index.IndexManager.query(IndexManager.java:392) 
    ... 

IndexManager.java:392使用reader對象(IndexReader例如,全局唯一的)

IndexManager.query方法具有大量的併發請求,所有請求使用一個全局唯一IndexReader實例(reader對象)

enter image description here

我需要關閉oldReader只是因爲:

參考:

我該如何解決這個問題?

+0

確定讀者在致電openIfChanged之前沒有關閉嗎? – vikas 2012-07-08 12:17:43

+0

什麼是併發設置?如果可以同時執行此代碼,則可能會有許多問題。無論如何,你不應該自己實現這個,因爲Lucene已經[提供自己的SearcherManager](http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/core/org/apache/lucene/search/ SearcherManager.html)。 – 2012-07-08 12:58:42

+0

@vikas我的問題描述了錯誤,我必須修改和重寫問題 – Koerr 2012-07-08 14:50:44

回答

5

看NRTManager和SearcherManager

reader.decRef()自動關閉的讀者。你真的不必自己處理這個問題。

+0

謝謝@ MJB,這就是我想要的 – Koerr 2012-07-09 08:34:45

0

如果在閱讀器(oldReader)上工作,我假設搜索器(以後稱爲oldSearcher),在這種情況下,當它關閉時它也會關閉它,因此您不需要關閉它, oldSearcher .close()就足夠了。

+0

閉合IndexSearcher不關閉基礎IndexReader,除非它使用隱式讀取器。 [參考文獻](http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/core/org/apache/lucene/search/IndexSearcher.html#close%28%29)。 – vikas 2012-07-08 12:16:57

+0

你說得對,那就是我說的 - 我假設他建立了搜索者,所以它會使用讀者隱含的。 – shem 2012-07-08 12:22:16

+0

隱式讀取器意味着IndexSearcher通過提供包含索引的目錄的路徑來創建。因此,如果oldSearcher是使用[this]創建的(http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/core/org/apache/lucene/search/IndexSearcher.html#IndexSearcher%28org。 apache.lucene.store.Directory%29)構造函數和讀取器稍後從中檢索,它會關閉底層的讀取器。 – vikas 2012-07-08 12:36:55

0

我根本沒有看到oldReader和oldSearcher在做什麼!!!!! 你就不能刪除它們連同它們close() 如果您仍然需要它們,那麼我的賭注是,oldSearcher某種程度上關係到oldReader,因此呼籲oldSearcher也導致關閉oldReader這就是爲什麼你得到的異常 那是close()整個代碼的大部分,還是你簡化它?如果是對第一,那麼就刪除oldReader和oldSearcher共

乾杯

+0

謝謝你的回答,在我的問題描述錯誤之前,我修復並重寫了問題 – Koerr 2012-07-08 14:57:13

+0

,儘管我強烈地相信第二次close()調用是在封閉的流上進行的。由第一個close()引起。嘗試在oldReader上檢查ifClosed()或其他東西,因爲其他用戶提到過,oldReader和oldSearcher一個用於初始化另一個,所以關閉其中一個,也關閉另一個 – 2012-07-08 15:19:46

+0

我刪除'oldSearcher.close()'只運行' oldReader.close()'問題是一樣的 – Koerr 2012-07-08 15:23:27

0

看看的的IndexReader引用計數的方法。 i。e當您使用 reader.incRef();實例化新的IndexSearcher時,請增加參考計數,並在完成搜索結果後減少參考計數,最好使用reader.decRef()的try catch方法的finally語句;當引用數爲0

+0

我強烈建議你看看lucene的第361-364頁,在Action book – amas 2012-07-09 03:14:33

3

您需要對寫入操作和public static變量之間施加happens-before關係,然後從其他線程讀取它們。如果你使用多個var,你會遇到原子性的問題,所以我建議你只使用一個var,因爲這是你所需要的。

簡單地說,這會爲你工作:

public class SearcherManager 
{ 
    public static volatile IndexSearcher searcher; 

    private static void reopen() { 
    // your code, just without assignment to reader 
    } 
} 

的關鍵是volatile修改。在寫入var之前,一定要完全初始化所有內容,但在寫入—之後關閉舊對象,換句話說,請確保按照現在的方式繼續進行操作:)

但是,作爲@MJB在他的回答中注意到,你應該真的不會這樣做,因爲它全部內置到Lucene中。查看Javadoc on NRTManagerReopenThread以獲取所需的全部信息,包括完整的代碼示例。