com.browseengine.bobo.api.MultiBoboBrowser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bobo-browse Show documentation
Show all versions of bobo-browse Show documentation
Bobo is a Faceted Search implementation written purely in Java, an extension of Apache Lucene
The newest version!
package com.browseengine.bobo.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.log4j.Logger;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.MultiReader;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.similarities.Similarity;
import com.browseengine.bobo.facets.FacetHandler;
import com.browseengine.bobo.sort.SortCollector;
/**
* Provides implementation of Browser for multiple Browser instances
*/
public class MultiBoboBrowser extends MultiReader implements Browsable {
private static Logger logger = Logger.getLogger(MultiBoboBrowser.class);
protected final Browsable[] _subBrowsers;
/**
*
* @param browsers
* Browsers to search on
* @throws IOException
*/
public MultiBoboBrowser(Browsable[] browsers) throws IOException {
super(getSegmentReaders(browsers), false);
_subBrowsers = browsers;
}
private static IndexReader[] getSegmentReaders(Browsable[] browsers) {
IndexReader[] readers = new IndexReader[browsers.length];
for (int i = 0; i < browsers.length; ++i) {
readers[i] = browsers[i].getIndexReader();
}
return readers;
}
@Override
public void browse(BrowseRequest req, final Collector hc, Map facetMap,
int start) throws BrowseException {
// index empty
if (_subBrowsers == null || _subBrowsers.length == 0) {
return;
}
try {
Query q = req.getQuery();
MatchAllDocsQuery matchAllDocsQuery = new MatchAllDocsQuery();
if (q == null) {
q = matchAllDocsQuery;
} else if (!(q instanceof MatchAllDocsQuery)) {
// MatchAllQuery is needed to filter out the deleted docids, that reside in
// ZoieSegmentReader and are not visible on Bobo level
matchAllDocsQuery.setBoost(0f);
q = QueriesSupport.combineAnd(matchAllDocsQuery, q);
}
req.setQuery(q);
} catch (Exception ioe) {
throw new BrowseException(ioe.getMessage(), ioe);
}
Map> mergedMap = new HashMap>();
try {
Map facetColMap = new HashMap();
for (int i = 0; i < _subBrowsers.length; i++) {
try {
_subBrowsers[i].browse(req, hc, facetColMap, (start + readerBase(i)));
} finally {
Set> entries = facetColMap.entrySet();
for (Entry entry : entries) {
String name = entry.getKey();
FacetAccessible facetAccessor = entry.getValue();
List list = mergedMap.get(name);
if (list == null) {
list = new ArrayList(_subBrowsers.length);
mergedMap.put(name, list);
}
list.add(facetAccessor);
}
facetColMap.clear();
}
}
} finally {
if (req.getMapReduceWrapper() != null) {
req.getMapReduceWrapper().finalizePartition();
}
Set>> entries = mergedMap.entrySet();
for (Entry> entry : entries) {
String name = entry.getKey();
FacetHandler> handler = getFacetHandler(name);
try {
List subList = entry.getValue();
if (subList != null) {
FacetAccessible merged = handler.merge(req.getFacetSpec(name), subList);
facetMap.put(name, merged);
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
}
/**
* Generate a merged BrowseResult from the given BrowseRequest
* @param req
* BrowseRequest for generating the facets
* @return BrowseResult of the results of the BrowseRequest
*/
@Override
public BrowseResult browse(BrowseRequest req) throws BrowseException {
final BrowseResult result = new BrowseResult();
// index empty
if (_subBrowsers == null || _subBrowsers.length == 0) {
return result;
}
long start = System.currentTimeMillis();
int offset = req.getOffset();
int count = req.getCount();
if (offset < 0 || count < 0) {
throw new IllegalArgumentException("both offset and count must be > 0: " + offset + "/"
+ count);
}
SortCollector collector = getSortCollector(req.getSort(), req.getQuery(), offset, count,
req.isFetchStoredFields(), req.getTermVectorsToFetch(), req.getGroupBy(), req.getMaxPerGroup(),
req.getCollectDocIdCache());
Map facetCollectors = new HashMap();
browse(req, collector, facetCollectors, 0);
if (req.getMapReduceWrapper() != null) {
result.setMapReduceResult(req.getMapReduceWrapper().getResult());
}
BrowseHit[] hits = null;
try {
hits = collector.topDocs();
} catch (IOException e) {
logger.error(e.getMessage(), e);
result.addError(e.getMessage());
hits = new BrowseHit[0];
}
Query q = req.getQuery();
if (req.isShowExplanation()) {
for (BrowseHit hit : hits) {
try {
int doc = hit.getDocid();
int idx = readerIndex(doc);
int deBasedDoc = doc - readerBase(idx);
Explanation expl = _subBrowsers[idx].explain(q, deBasedDoc);
hit.setExplanation(expl);
} catch (IOException e) {
logger.error(e.getMessage(), e);
result.addError(e.getMessage());
}
}
}
result.setHits(hits);
result.setNumHits(collector.getTotalHits());
result.setNumGroups(collector.getTotalGroups());
result.setGroupAccessibles(collector.getGroupAccessibles());
result.setSortCollector(collector);
result.setTotalDocs(numDocs());
result.addAll(facetCollectors);
long end = System.currentTimeMillis();
result.setTime(end - start);
// set the transaction ID to trace transactions
result.setTid(req.getTid());
return result;
}
/**
* Return the values of a field for the given doc
*
*/
@Override
public String[] getFieldVal(int docid, final String fieldname) throws IOException {
int i = readerIndex(docid);
Browsable browser = _subBrowsers[i];
return browser.getFieldVal(docid - readerBase(i), fieldname);
}
@Override
public Object[] getRawFieldVal(int docid, String fieldname) throws IOException {
int i = readerIndex(docid);
Browsable browser = _subBrowsers[i];
return browser.getRawFieldVal(docid - readerBase(i), fieldname);
}
/**
* Compare BrowseFacets by their value
*/
public static class BrowseFacetValueComparator implements Comparator {
@Override
public int compare(BrowseFacet o1, BrowseFacet o2) {
return o1.getValue().compareTo(o2.getValue());
}
}
/**
* Gets the sub-browser for a given docid
*
* @param docid
* @return sub-browser instance
*/
public Browsable subBrowser(int docid) {
int i = readerIndex(docid);
return _subBrowsers[i];
}
@Override
public void setSimilarity(Similarity similarity) {
for (Browsable subBrowser : _subBrowsers) {
subBrowser.setSimilarity(similarity);
}
}
@Override
public Set getFacetNames() {
Set names = new HashSet();
for (Browsable subBrowser : _subBrowsers) {
names.addAll(subBrowser.getFacetNames());
}
return names;
}
@Override
public FacetHandler> getFacetHandler(String name) {
for (Browsable subBrowser : _subBrowsers) {
FacetHandler> subHandler = subBrowser.getFacetHandler(name);
if (subHandler != null) return subHandler;
}
return null;
}
@Override
public Map> getFacetHandlerMap() {
HashMap> map = new HashMap>();
for (Browsable subBrowser : _subBrowsers) {
map.putAll(subBrowser.getFacetHandlerMap());
}
return map;
}
@Override
public void setFacetHandler(FacetHandler> facetHandler) throws IOException {
for (Browsable subBrowser : _subBrowsers) {
subBrowser.setFacetHandler(facetHandler);
}
}
@Override
public SortCollector getSortCollector(SortField[] sort, Query q, int offset, int count,
boolean fetchStoredFields, Set termVectorsToFetch, String[] groupBy, int maxPerGroup,
boolean collectDocIdCache) {
if (_subBrowsers.length == 1) {
return _subBrowsers[0].getSortCollector(sort, q, offset, count, fetchStoredFields,
termVectorsToFetch, groupBy, maxPerGroup, collectDocIdCache);
}
return SortCollector.buildSortCollector(this, q, sort, offset, count, fetchStoredFields,
termVectorsToFetch, groupBy, maxPerGroup, collectDocIdCache);
}
@Override
public void doClose() throws IOException {
super.doClose();
for (Browsable subBrowser : _subBrowsers) {
subBrowser.doClose();
}
}
@Override
public IndexReader getIndexReader() {
return this;
}
@Override
public Explanation explain(Query q, int deBasedDoc) throws IOException {
throw new UnsupportedOperationException();
}
}