package org.compass.core.lucene.engine;
import java.io.IOException;
import java.util.List;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MultiSearcher;
import org.apache.lucene.search.Searchable;
import org.apache.lucene.search.Searcher;
import org.compass.core.engine.SearchEngineException;
import org.compass.core.engine.SearchEngineInternalSearch;
import org.compass.core.lucene.engine.manager.LuceneIndexHolder;
import org.compass.core.lucene.search.CacheableMultiReader;
/**
* A Lucene specific search "internals", allowing for Lucene {@link IndexReader} and {@link Searcher}
* access.
*
* @author kimchy
*/
public class LuceneSearchEngineInternalSearch implements SearchEngineInternalSearch, LuceneDelegatedClose {
private LuceneSearchEngine searchEngine;
private Searcher searcher;
private IndexReader indexReader;
private List<LuceneIndexHolder> indexHoldersToClose;
private boolean closeReader;
private boolean closeSearcher;
private boolean closed;
public LuceneSearchEngineInternalSearch(LuceneSearchEngine searchEngine, List<LuceneIndexHolder> indexHolders) {
this.searchEngine = searchEngine;
this.indexHoldersToClose = indexHolders;
}
public LuceneSearchEngineInternalSearch(LuceneSearchEngine searchEngine, MultiSearcher searcher, List<LuceneIndexHolder> indexHolders) {
this.searchEngine = searchEngine;
this.searcher = searcher;
this.indexHoldersToClose = indexHolders;
Searchable[] searchables = searcher.getSearchables();
IndexReader[] readers = new IndexReader[searchables.length];
for (int i = 0; i < searchables.length; i++) {
readers[i] = ((IndexSearcher) searchables[i]).getIndexReader();
}
indexReader = new CacheableMultiReader(readers, false);
this.closeReader = true;
this.closeSearcher = true;
}
public LuceneSearchEngineInternalSearch(LuceneSearchEngine searchEngine, LuceneIndexHolder indexHolder, List<LuceneIndexHolder> indexHolders) {
this.searchEngine = searchEngine;
this.searcher = indexHolder.getIndexSearcher();
this.indexReader = indexHolder.getIndexReader();
this.indexHoldersToClose = indexHolders;
this.closeReader = false;
this.closeSearcher = false;
}
/**
* Creates a new instance, with a searcher and index holders which will be used
* to release when calling close.
*/
public LuceneSearchEngineInternalSearch(LuceneSearchEngine searchEngine, IndexReader indexReader, Searcher searcher, List<LuceneIndexHolder> indexHolders) {
this.searchEngine = searchEngine;
this.indexReader = indexReader;
this.searcher = searcher;
this.indexHoldersToClose = indexHolders;
this.closeReader = true;
this.closeSearcher = true;
}
/**
* Returns <code>true</code> if it represents an empty index scope.
*/
public boolean isEmpty() {
return searcher == null;
}
/**
* Returns a Lucene {@link Searcher}.
*/
public Searcher getSearcher() {
return this.searcher;
}
/**
* Returns a Lucene {@link IndexReader}.
*/
public IndexReader getReader() throws SearchEngineException {
return this.indexReader;
}
/**
* [Intenral]: Closes without removing the delegate.
*/
public void closeDelegate() throws SearchEngineException {
close(false);
}
/**
* Closes the internal search. Note, does not require to be called here since
* will automatically be called on transaction commit / rollback.
*/
public void close() throws SearchEngineException {
close(true);
}
/**
* Closes this instance of Lucene search "internals". This is an optional operation
* since Compass will take care of closing it when commit/rollback is called on the
* transaction.
*/
private void close(boolean removeDelegate) throws SearchEngineException {
if (closed) {
return;
}
closed = true;
if (removeDelegate) {
searchEngine.removeDelegatedClose(this);
}
if (searcher != null && closeSearcher) {
try {
searcher.close();
} catch (IOException e) {
// ignore
}
}
if (indexReader != null && closeReader) {
try {
indexReader.close();
} catch (IOException e) {
// ignore
}
}
if (indexHoldersToClose != null) {
for (LuceneIndexHolder indexHolder : indexHoldersToClose) {
indexHolder.release();
}
}
}
}