2012-07-08 245 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以获取所需的全部信息,包括完整的代码示例。