package org.apache.lucene.facet.search;
import java.io.IOException;
import java.util.List;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.facet.search.params.FacetSearchParams;
import org.apache.lucene.facet.search.params.FacetRequest;
import org.apache.lucene.facet.search.results.FacetResult;
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
/*
* 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.
*/
/**
* Driver for Accumulating facets of faceted search requests over given
* documents.
*
* @lucene.experimental
*/
public abstract class FacetsAccumulator {
/**
* Default threshold for using the complements optimization.
* If accumulating facets for a document set larger than this ratio of the index size than
* perform the complement optimization.
* @see #setComplementThreshold(double) for more info on the complements optimization.
*/
public static final double DEFAULT_COMPLEMENT_THRESHOLD = 0.6;
/**
* Passing this to {@link #setComplementThreshold(double)} will disable using complement optimization.
*/
public static final double DISABLE_COMPLEMENT = Double.POSITIVE_INFINITY; // > 1 actually
/**
* Passing this to {@link #setComplementThreshold(double)} will force using complement optimization.
*/
public static final double FORCE_COMPLEMENT = 0; // <=0
private double complementThreshold = DEFAULT_COMPLEMENT_THRESHOLD;
protected final TaxonomyReader taxonomyReader;
protected final IndexReader indexReader;
protected FacetSearchParams searchParams;
private boolean allowLabeling = true;
public FacetsAccumulator(FacetSearchParams searchParams,
IndexReader indexReader,
TaxonomyReader taxonomyReader) {
this.indexReader = indexReader;
this.taxonomyReader = taxonomyReader;
this.searchParams = searchParams;
}
/**
* Accumulate facets over given documents, according to facet requests in effect.
* @param docids documents (and their scores) for which facets are Accumulated.
* @return Accumulated facets.
* @throws IOException on error.
*/
// internal API note: it was considered to move the docids into the constructor as well,
// but this prevents nice extension capabilities, especially in the way that
// Sampling Accumulator works with the (any) delegated accumulator.
public abstract List<FacetResult> accumulate(ScoredDocIDs docids) throws IOException;
/**
* Returns the complement threshold.
* @see #setComplementThreshold(double)
*/
public double getComplementThreshold() {
return complementThreshold;
}
/**
* Set the complement threshold.
* This threshold will dictate whether the complements optimization is applied.
* The optimization is to count for less documents. It is useful when the same
* FacetSearchParams are used for varying sets of documents. The first time
* complements is used the "total counts" are computed - counting for all the
* documents in the collection. Then, only the complementing set of documents
* is considered, and used to decrement from the overall counts, thereby
* walking through less documents, which is faster.
* <p>
* For the default settings see {@link #DEFAULT_COMPLEMENT_THRESHOLD}.
* <p>
* To forcing complements in all cases pass {@link #FORCE_COMPLEMENT}.
* This is mostly useful for testing purposes, as forcing complements when only
* tiny fraction of available documents match the query does not make sense and
* would incur performance degradations.
* <p>
* To disable complements pass {@link #DISABLE_COMPLEMENT}.
* @param complementThreshold the complement threshold to set
* @see #getComplementThreshold()
*/
public void setComplementThreshold(double complementThreshold) {
this.complementThreshold = complementThreshold;
}
/**
* Check if labeling is allowed for this accumulator.
* <p>
* By default labeling is allowed.
* This allows one accumulator to invoke other accumulators for accumulation
* but keep to itself the responsibility of labeling.
* This might br handy since labeling is a costly operation.
* @return true of labeling is allowed for this accumulator
* @see #setAllowLabeling(boolean)
*/
protected boolean isAllowLabeling() {
return allowLabeling;
}
/**
* Set whether labeling is allowed for this accumulator.
* @param allowLabeling new setting for allow labeling
* @see #isAllowLabeling()
*/
protected void setAllowLabeling(boolean allowLabeling) {
this.allowLabeling = allowLabeling;
}
/** check if all requests are complementable */
protected boolean mayComplement() {
for (FacetRequest freq:searchParams.getFacetRequests()) {
if (!freq.supportsComplements()) {
return false;
}
}
return true;
}
}