package com.browseengine.bobo.facets.filter; import java.io.IOException; import org.apache.lucene.search.DocIdSetIterator; import com.browseengine.bobo.api.BoboSegmentReader; import com.browseengine.bobo.docidset.EmptyDocIdSet; import com.browseengine.bobo.docidset.RandomAccessDocIdSet; import com.browseengine.bobo.facets.FacetHandler; import com.browseengine.bobo.facets.data.FacetDataCache; import com.browseengine.bobo.util.BigSegmentedArray; public class CompactMultiValueFacetFilter extends RandomAccessFilter { private final FacetHandler<FacetDataCache<?>> _facetHandler; private final String[] _vals; public CompactMultiValueFacetFilter(FacetHandler<FacetDataCache<?>> facetHandler, String val) { this(facetHandler, new String[] { val }); } public CompactMultiValueFacetFilter(FacetHandler<FacetDataCache<?>> facetHandler, String[] vals) { _facetHandler = facetHandler; _vals = vals; } @SuppressWarnings("unchecked") @Override public double getFacetSelectivity(BoboSegmentReader reader) { double selectivity = 0; FacetDataCache<String> dataCache = (FacetDataCache<String>) _facetHandler.getFacetData(reader); int[] idxes = FacetDataCache.convert(dataCache, _vals); if (idxes == null) { return 0.0; } int accumFreq = 0; for (int idx : idxes) { accumFreq += dataCache.freqs[idx]; } int total = reader.maxDoc(); selectivity = (double) accumFreq / (double) total; if (selectivity > 0.999) { selectivity = 1.0; } return selectivity; } private final static class CompactMultiValueFacetDocIdSetIterator extends DocIdSetIterator { private final int _bits; private int _doc; private int _maxID; private final BigSegmentedArray _orderArray; public CompactMultiValueFacetDocIdSetIterator(FacetDataCache<?> dataCache, int[] index, int bits) { _bits = bits; _doc = Integer.MAX_VALUE; _maxID = -1; _orderArray = dataCache.orderArray; for (int i : index) { if (_doc > dataCache.minIDs[i]) { _doc = dataCache.minIDs[i]; } if (_maxID < dataCache.maxIDs[i]) { _maxID = dataCache.maxIDs[i]; } } _doc--; if (_doc < 0) _doc = -1; } @Override public final int docID() { return _doc; } @Override public final int nextDoc() throws IOException { return (_doc = (_doc < _maxID ? _orderArray.findBits(_bits, (_doc + 1), _maxID) : NO_MORE_DOCS)); } @Override public final int advance(int id) throws IOException { if (_doc < id) { return (_doc = (id <= _maxID ? _orderArray.findBits(_bits, id, _maxID) : NO_MORE_DOCS)); } return nextDoc(); } @Override public long cost() { // TODO Auto-generated method stub return 0; } } @SuppressWarnings("unchecked") @Override public RandomAccessDocIdSet getRandomAccessDocIdSet(final BoboSegmentReader reader) throws IOException { final FacetDataCache<String> dataCache = (FacetDataCache<String>) _facetHandler .getFacetData(reader); final int[] indexes = FacetDataCache.convert(dataCache, _vals); int bits; bits = 0x0; for (int i : indexes) { bits |= 0x00000001 << (i - 1); } final int finalBits = bits; final BigSegmentedArray orderArray = dataCache.orderArray; if (indexes.length == 0) { return EmptyDocIdSet.getInstance(); } else { return new RandomAccessDocIdSet() { @Override public DocIdSetIterator iterator() { return new CompactMultiValueFacetDocIdSetIterator(dataCache, indexes, finalBits); } @Override final public boolean get(int docId) { return (orderArray.get(docId) & finalBits) != 0x0; } }; } } }