2012-07-08 6 views
3

Ma question est très simple, Lorsque l'utilisation IndexReader.openIfChanged (reader) remplacer le précédent reader, Comment fermer en toute sécurité le oldReader?Comment fermer un IndexReader en toute sécurité?

Voici le code: (utiliser 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 
} 

Ce code dans un fil de deamon, toutes les 5 secondes temps d'exécution

IndexReader instance (objet reader) est unique au monde

Depuis ce changement, je reçois une exception:

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 utilisant l'objet reader (IndexReader exemple, globalement unique)

procédé IndexManager.query a un grand nombre de demandes simultanées, toutes les demandes d'utiliser un IndexReader instance unique global (reader objet)

enter image description here

I besoin de fermer oldReader juste parce que:

Référence:

Comment puis-je résoudre ce problème?

+0

Etes-vous sûr que le lecteur n'est pas fermé avant l'appel à openIfChanged? – vikas

+0

Et quel est votre paramètre de concurrence? Si ce code peut être exécuté de manière concomitante, il y a beaucoup de choses qui peuvent ne pas fonctionner. Quoi qu'il en soit, vous ne devriez pas l'implémenter vous-même puisque Lucene [fournit déjà son propre SearcherManager] (http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/core/org/apache/lucene/search/ SearcherManager.html). –

+0

@vikas Ma question décrit l'erreur, je dois réviser et réécrire la question – Koerr

Répondre

5

Regardez NRTManager et SearcherManager. Vous n'avez vraiment pas à gérer cela vous-même.

+0

merci @ MJB, c'est ce que je veux – Koerr

0

Je suppose le chercheur (que plus tard arbitré comme oldSearcher) si travaillant sur le lecteur (oldReader), dans ce cas quand vous le fermez aussi le lecteur qu'il emploie, ainsi vous ne devez pas le fermer, oldSearcher .close() est suffisant.

+0

Clôture IndexSearcher ne ferme pas le IndexReader sous-jacent sauf s'il utilise un lecteur implicite. [Référence] (http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/core/org/apache/lucene/search/IndexSearcher.html#close%28%29). – vikas

+0

Vous avez raison, c'est ce que j'ai dit - je suppose qu'il construit le chercheur de sorte qu'il utilisera le lecteur implicite. – shem

+0

Un lecteur implicite signifie que IndexSearcher est créé en fournissant le chemin d'accès au répertoire contenant les index. Donc, si oldSearcher a été créé en utilisant [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) constructeur et le lecteur a été récupéré plus tard, il fermerait le lecteur sous-jacent. – vikas

0

Je ne vois pas du tout ce que oldReader et oldSearcher font du tout !!!!! Vous ne pouvez pas simplement les supprimer avec leurs close() Si vous en avez toujours besoin, alors je parie que oldSearcher est en quelque sorte lié à oldReader, donc appeler close() sur oldSearcher provoque également la fermeture de oldReader, c'est pourquoi vous obtenez l'exception l'ensemble du code, ou l'avez-vous simplifié? si oui à la première, puis supprimez oldReader et oldSearcher en tout

Vive

+0

merci pour la réponse, Avant ma question pour décrire l'erreur, j'ai corrigé et réécrire la question – Koerr

+0

mais je crois fermement que le second close() appel est fait sur un flux fermé. causé par la première fermeture(). Essayez de vérifier ifClosed() ou quelque chose sur oldReader, puisque les autres utilisateurs ont mentionné, oldReader et oldSearcher on est utilisé pour initialiser l'autre, donc en fermant l'un, ferme également l'autre –

+0

J'ai enlevé 'oldSearcher.close()' seulement exécuté ' oldReader.close() 'le problème est le même – Koerr

0

Jetez un oeil sur les méthodes de comptage de référence IndexReader. i.e Augmentez le nombre de références lorsque vous instanciez un nouveau IndexSearcher avec reader.incRef(); et diminuez-le lorsque vous avez terminé avec les résultats de la recherche et de préférence dans une instruction finally d'une méthode try catch avec reader.decRef();

reader.decRef() ferme automatiquement le lecteur lorsque le nombre de références est 0.

+0

Je vous recommande fortement de jeter un oeil à la page 361-364 de Lucene dans le livre d'action – amas

3

Vous devez imposer la relation happens-before entre les écritures aux variables public static et les lectures ultérieures d'autres threads. Si vous utilisez plus d'un var, vous aurez le problème de l'atomicité, donc je vous recommande d'utiliser un seul var car c'est tout ce dont vous avez besoin.

Simplement, cela fonctionne pour vous:

public class SearcherManager 
{ 
    public static volatile IndexSearcher searcher; 

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

La clé est le modificateur volatile. Assurez-vous de complètement initialiser tout avant d'écrire dans le var, mais faites la fermeture des anciens objets après l'écriture — en d'autres termes, assurez-vous de continuer à le faire comme vous le faites maintenant :)

Mais, comme @MJB note dans sa réponse, vous devriez vraiment ne pas le faire, car il est tout intégré dans Lucene. Consultez le Javadoc on NRTManagerReopenThread pour obtenir toutes les informations dont vous avez besoin, y compris un exemple de code complet.

Questions connexes