package org.apache.lucene.facet.search;
import java.io.IOException;
import org.apache.lucene.facet.search.params.FacetRequest;
import org.apache.lucene.facet.search.results.FacetResult;
import org.apache.lucene.facet.search.results.FacetResultNode;
import org.apache.lucene.facet.search.results.IntermediateFacetResult;
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.
*/
/**
* Handler for facet results.
* <p>
* The facet results handler provided by the {@link FacetRequest} to
* a {@link FacetsAccumulator}.
* <p>
* First it is used by {@link FacetsAccumulator} to obtain a temporary
* facet result for each partition and to merge results of several partitions.
* <p>
* Later the accumulator invokes the handler to render the results, creating
* {@link FacetResult} objects.
* <p>
* Last the accumulator invokes the handler to label final results.
*
* @lucene.experimental
*/
public abstract class FacetResultsHandler {
/** Taxonomy for which facets are handled */
protected final TaxonomyReader taxonomyReader;
/**
* Facet request served by this handler.
*/
protected final FacetRequest facetRequest;
/**
* Create a faceted search handler.
* @param taxonomyReader See {@link #getTaxonomyReader()}.
* @param facetRequest See {@link #getFacetRequest()}.
*/
public FacetResultsHandler(TaxonomyReader taxonomyReader,
FacetRequest facetRequest) {
this.taxonomyReader = taxonomyReader;
this.facetRequest = facetRequest;
}
/**
* Fetch results of a single partition, given facet arrays for that partition,
* and based on the matching documents and faceted search parameters.
*
* @param arrays
* facet arrays for the certain partition
* @param offset
* offset in input arrays where partition starts
* @return temporary facet result, potentially, to be passed back to
* <b>this</b> result handler for merging, or <b>null</b> in case that
* constructor parameter, <code>facetRequest</code>, requests an
* illegal FacetResult, like, e.g., a root node category path that
* does not exist in constructor parameter <code>taxonomyReader</code>
* .
* @throws IOException
* on error
*/
public abstract IntermediateFacetResult fetchPartitionResult(FacetArrays arrays, int offset) throws IOException;
/**
* Merge results of several facet partitions. Logic of the merge is undefined
* and open for interpretations. For example, a merge implementation could
* keep top K results. Passed {@link IntermediateFacetResult} must be ones
* that were created by this handler otherwise a {@link ClassCastException} is
* thrown. In addition, all passed {@link IntermediateFacetResult} must have
* the same {@link FacetRequest} otherwise an {@link IllegalArgumentException}
* is thrown.
*
* @param tmpResults one or more temporary results created by <b>this</b>
* handler.
* @return temporary facet result that represents to union, as specified by
* <b>this</b> handler, of the input temporary facet results.
* @throws IOException on error.
* @throws ClassCastException if the temporary result passed was not created
* by this handler
* @throws IllegalArgumentException if passed <code>facetResults</code> do not
* have the same {@link FacetRequest}
* @see IntermediateFacetResult#getFacetRequest()
*/
public abstract IntermediateFacetResult mergeResults(IntermediateFacetResult... tmpResults)
throws IOException, ClassCastException, IllegalArgumentException;
/**
* Create a facet result from the temporary result.
* @param tmpResult temporary result to be rendered as a {@link FacetResult}
* @throws IOException on error.
*/
public abstract FacetResult renderFacetResult(IntermediateFacetResult tmpResult) throws IOException ;
/**
* Perform any rearrangement as required on a facet result that has changed after
* it was rendered.
* <P>
* Possible use case: a sampling facets accumulator invoked another
* other facets accumulator on a sample set of documents, obtained
* rendered facet results, fixed their counts, and now it is needed
* to sort the results differently according to the fixed counts.
* @param facetResult result to be rearranged.
* @see FacetResultNode#setValue(double)
*/
public abstract FacetResult rearrangeFacetResult(FacetResult facetResult);
/**
* Label results according to settings in {@link FacetRequest},
* such as {@link FacetRequest#getNumLabel()}.
* Usually invoked by {@link FacetsAccumulator#accumulate(ScoredDocIDs)}
* @param facetResult facet result to be labeled.
* @throws IOException on error
*/
public abstract void labelResult (FacetResult facetResult) throws IOException;
/** Return taxonomy reader used for current facets accumulation operation. */
public final TaxonomyReader getTaxonomyReader() {
return this.taxonomyReader;
}
/** Return the facet request served by this handler. */
public final FacetRequest getFacetRequest() {
return this.facetRequest;
}
/**
* Check if an array contains the partition which contains ordinal
*
* @param ordinal
* checked facet
* @param facetArrays
* facet arrays for the certain partition
* @param offset
* offset in input arrays where partition starts
*/
protected boolean isSelfPartition (int ordinal, FacetArrays facetArrays, int offset) {
int partitionSize = facetArrays.getArraysLength();
return ordinal / partitionSize == offset / partitionSize;
}
}