/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.solr.search; import org.apache.lucene.index.AtomicReader; import org.apache.solr.common.SolrException; import org.apache.lucene.util.Bits; import org.apache.lucene.util.FixedBitSet; import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.Filter; import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.BitsFilteredDocIdSet; import org.apache.lucene.index.AtomicReaderContext; /** A base class that may be usefull for implementing DocSets */ abstract class DocSetBase implements DocSet { // Not implemented efficiently... for testing purposes only @Override public boolean equals(Object obj) { if (!(obj instanceof DocSet)) return false; DocSet other = (DocSet)obj; if (this.size() != other.size()) return false; if (this instanceof DocList && other instanceof DocList) { // compare ordering DocIterator i1=this.iterator(); DocIterator i2=other.iterator(); while(i1.hasNext() && i2.hasNext()) { if (i1.nextDoc() != i2.nextDoc()) return false; } return true; // don't compare matches } // if (this.size() != other.size()) return false; return this.getBits().equals(other.getBits()); } /** * @throws SolrException Base implementation does not allow modifications */ @Override public void add(int doc) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,"Unsupported Operation"); } /** * @throws SolrException Base implementation does not allow modifications */ @Override public void addUnique(int doc) { throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,"Unsupported Operation"); } /** * Inefficient base implementation. * * @see BitDocSet#getBits */ @Override public FixedBitSet getBits() { FixedBitSet bits = new FixedBitSet(64); for (DocIterator iter = iterator(); iter.hasNext();) { int nextDoc = iter.nextDoc(); bits = FixedBitSet.ensureCapacity(bits, nextDoc); bits.set(nextDoc); } return bits; } @Override public DocSet intersection(DocSet other) { // intersection is overloaded in the smaller DocSets to be more // efficient, so dispatch off of it instead. if (!(other instanceof BitDocSet)) { return other.intersection(this); } // Default... handle with bitsets. FixedBitSet newbits = (FixedBitSet)(this.getBits().clone()); newbits.and(other.getBits()); return new BitDocSet(newbits); } @Override public boolean intersects(DocSet other) { // intersection is overloaded in the smaller DocSets to be more // efficient, so dispatch off of it instead. if (!(other instanceof BitDocSet)) { return other.intersects(this); } // less efficient way: get the intersection size return intersectionSize(other) > 0; } @Override public DocSet union(DocSet other) { if (other instanceof BitDocSet) { return other.union(this); } FixedBitSet newbits = (FixedBitSet)(this.getBits().clone()); FixedBitSet otherbits = other.getBits(); newbits = FixedBitSet.ensureCapacity(newbits, otherbits.length()); newbits.or(otherbits); return new BitDocSet(newbits); } @Override public int intersectionSize(DocSet other) { // intersection is overloaded in the smaller DocSets to be more // efficient, so dispatch off of it instead. if (!(other instanceof BitDocSet)) { return other.intersectionSize(this); } // less efficient way: do the intersection then get it's size return intersection(other).size(); } @Override public int unionSize(DocSet other) { return this.size() + other.size() - this.intersectionSize(other); } @Override public DocSet andNot(DocSet other) { FixedBitSet newbits = (FixedBitSet)(this.getBits().clone()); newbits.andNot(other.getBits()); return new BitDocSet(newbits); } @Override public int andNotSize(DocSet other) { return this.size() - this.intersectionSize(other); } @Override public Filter getTopFilter() { final FixedBitSet bs = getBits(); return new Filter() { @Override public DocIdSet getDocIdSet(final AtomicReaderContext context, Bits acceptDocs) { AtomicReader reader = context.reader(); // all Solr DocSets that are used as filters only include live docs final Bits acceptDocs2 = acceptDocs == null ? null : (reader.getLiveDocs() == acceptDocs ? null : acceptDocs); if (context.isTopLevel) { return BitsFilteredDocIdSet.wrap(bs, acceptDocs); } final int base = context.docBase; final int maxDoc = reader.maxDoc(); final int max = base + maxDoc; // one past the max doc in this segment. return BitsFilteredDocIdSet.wrap(new DocIdSet() { @Override public DocIdSetIterator iterator() { return new DocIdSetIterator() { int pos=base-1; int adjustedDoc=-1; @Override public int docID() { return adjustedDoc; } @Override public int nextDoc() { pos = bs.nextSetBit(pos+1); return adjustedDoc = (pos>=0 && pos<max) ? pos-base : NO_MORE_DOCS; } @Override public int advance(int target) { if (target==NO_MORE_DOCS) return adjustedDoc=NO_MORE_DOCS; pos = bs.nextSetBit(target+base); return adjustedDoc = (pos>=0 && pos<max) ? pos-base : NO_MORE_DOCS; } @Override public long cost() { return bs.length(); } }; } @Override public boolean isCacheable() { return true; } @Override public Bits bits() { // sparse filters should not use random access return null; } }, acceptDocs2); } }; } @Override public void setBitsOn(FixedBitSet target) { DocIterator iter = iterator(); while (iter.hasNext()) { target.set(iter.nextDoc()); } } @Override public void setBitsOn(BitDocSetNative target) { DocIterator iter = iterator(); while (iter.hasNext()) { target.fastSet(iter.nextDoc()); } } @Override public void addAllTo(DocSet target) { DocIterator iter = iterator(); while (iter.hasNext()) { target.add(iter.nextDoc()); } } @Override public abstract DocSet clone(); // Default RefCount methods that do nothing @Override public int getRefCount() { return 1; } @Override public int incref() { return 1; } @Override public int decref() { return 1; } @Override public boolean tryIncref() { return true; } @Override public boolean tryDecref() { return true; } @Override // for AutoCloseable public void close() { } }