org.apache.solr.search.DocSetBase.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.solr.search.DocSetBase.java

Source

/*
 * 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.OpenBitSet;
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 OpenBitSet getBits() {
        OpenBitSet bits = new OpenBitSet();
        for (DocIterator iter = iterator(); iter.hasNext();) {
            bits.set(iter.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.
        OpenBitSet newbits = (OpenBitSet) (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) {
        OpenBitSet newbits = (OpenBitSet) (this.getBits().clone());
        newbits.or(other.getBits());
        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) {
        OpenBitSet newbits = (OpenBitSet) (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 OpenBitSet 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.capacity();
                            }
                        };
                    }

                    @Override
                    public boolean isCacheable() {
                        return true;
                    }

                    @Override
                    public Bits bits() {
                        // sparse filters should not use random access
                        return null;
                    }

                }, acceptDocs2);
            }
        };
    }

    @Override
    public void setBitsOn(OpenBitSet target) {
        DocIterator iter = iterator();
        while (iter.hasNext()) {
            target.fastSet(iter.nextDoc());
        }
    }

}