package spimedb.index; import com.google.common.collect.Iterators; import org.apache.lucene.document.Document; import org.apache.lucene.document.DocumentStoredFieldVisitor; import org.apache.lucene.facet.FacetResult; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.function.BiPredicate; /** * Created by me on 2/3/17. */ public final class SearchResult { public final static Logger logger = LoggerFactory.getLogger(SearchResult.class); private final TopDocs docs; private final IndexSearcher searcher; private final org.apache.lucene.search.Query query; public final FacetResult facets; public SearchResult(Query q, IndexSearcher searcher, @Nullable TopDocs docs, FacetResult facetResults) { this.query = q; this.searcher = searcher; this.facets = facetResults; this.docs = docs; logger.info("query({}) hits={}", query, docs != null ? docs.totalHits : 0); } public void forEach(BiPredicate<DObject, ScoreDoc> each) { forEachDocument((d, s) -> each.test(DObject.get(d), s)); } public void forEachDocument(BiPredicate<Document, ScoreDoc> each) { if (docs == null) return; final DocumentStoredFieldVisitor visitor = new DocumentStoredFieldVisitor(); IndexReader reader = searcher.getIndexReader(); Document d = visitor.getDocument(); for (ScoreDoc x : docs.scoreDocs) { d.clear(); try { reader.document(x.doc, visitor); if (!each.test(d, x)) break; } catch (IOException e) { SearchResult.logger.error("{}", e.getMessage()); } } } public Iterator<Document> docs() { if (docs == null) return Collections.emptyIterator(); final DocumentStoredFieldVisitor visitor = new DocumentStoredFieldVisitor(); IndexReader reader = searcher.getIndexReader(); Document d = visitor.getDocument(); return new SearchResultIterator(d, reader, visitor); } public void close() { synchronized (query) { if (searcher == null) return; try { searcher.getIndexReader().close(); } catch (IOException e) { logger.error("{}", e); } } } /** must be iterated completely for auto-close, or closed manually */ private class SearchResultIterator implements Iterator<Document> { private final Document d; private final IndexReader reader; private final DocumentStoredFieldVisitor visitor; Iterator<Document> ii; public SearchResultIterator(Document d, IndexReader reader, DocumentStoredFieldVisitor visitor) { this.d = d; this.reader = reader; this.visitor = visitor; ii = Iterators.transform(Iterators.forArray(docs.scoreDocs), sd -> { d.clear(); try { reader.document(sd.doc, visitor); } catch (IOException e) { logger.error("{} {}", sd, e); } return d; }); } @Override public boolean hasNext() { if (!ii.hasNext()) { close(); return false; } return true; } @Override public Document next() { return ii.next(); } } }