diff --git a/lucene/facet/src/java/org/apache/lucene/facet/search/FacetRequest.java b/lucene/facet/src/java/org/apache/lucene/facet/search/FacetRequest.java index fcdada09b0f..b63e621896a 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/search/FacetRequest.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/search/FacetRequest.java @@ -2,6 +2,7 @@ package org.apache.lucene.facet.search; import java.io.IOException; +import org.apache.lucene.facet.params.CategoryListParams.OrdinalPolicy; import org.apache.lucene.facet.taxonomy.CategoryPath; import org.apache.lucene.facet.taxonomy.TaxonomyReader; @@ -23,30 +24,36 @@ import org.apache.lucene.facet.taxonomy.TaxonomyReader; */ /** - * Request to accumulate facet information for a specified facet and possibly - * also some of its descendants, upto a specified depth. + * Defines an aggregation request for a category. Allows specifying the + * {@link #numResults number of child categories} to return as well as + * {@link #getSortOrder() which} categories to consider the "top" (highest or + * lowest ranking ones). *
- * The facet request additionally defines what information should - * be computed within the facet results, if and how should results - * be ordered, etc. - *
- * An example facet request is to look at all sub-categories of "Author", and - * return the 10 with the highest counts (sorted by decreasing count). + * If the category being aggregated is hierarchical, you can also specify the + * {@link #setDepth(int) depth} up which to aggregate child categories as well + * as how the result should be {@link #setResultMode(ResultMode) constructed}. * * @lucene.experimental */ public abstract class FacetRequest { /** - * Result structure manner of applying request's limits such as - * {@link FacetRequest#getNumLabel()} and {@link FacetRequest#numResults}. - * Only relevant when {@link FacetRequest#getDepth()} is > 1. + * When {@link FacetRequest#getDepth()} is greater than 1, defines the + * structure of the result as well as how constraints such as + * {@link FacetRequest#numResults} and {@link FacetRequest#getNumLabel()} are + * applied. */ public enum ResultMode { - /** Limits are applied per node, and the result has a full tree structure. */ + /** + * Constraints are applied per node, and the result has a full tree + * structure. Default result mode. + */ PER_NODE_IN_TREE, - /** Limits are applied globally, on total number of results, and the result has a flat structure. */ + /** + * Constraints are applied globally, on total number of results, and the + * result has a flat structure. + */ GLOBAL_FLAT } @@ -54,59 +61,50 @@ public abstract class FacetRequest { * Specifies which array of {@link FacetArrays} should be used to resolve * values. When set to {@link #INT} or {@link #FLOAT}, allows creating an * optimized {@link FacetResultsHandler}, which does not call - * {@link FacetRequest#getValueOf(FacetArrays, int)} for every ordinals. + * {@link FacetRequest#getValueOf(FacetArrays, int)} for every ordinal. *
* If set to {@link #BOTH}, the {@link FacetResultsHandler} will use * {@link FacetRequest#getValueOf(FacetArrays, int)} to resolve ordinal * values, although it is recommended that you consider writing a specialized * {@link FacetResultsHandler}. + *
+ * Can also be set to {@link #NONE}, to indicate that this
+ * {@link FacetRequest} does not use {@link FacetArrays} to aggregate its
+ * result categories. Such requests won't use {@link FacetResultsHandler}.
*/
- public enum FacetArraysSource { INT, FLOAT, BOTH }
+ public enum FacetArraysSource { INT, FLOAT, BOTH, NONE }
- /** Requested sort order for the results. */
+ /**
+ * Defines which categories to return. If {@link #DESCENDING} (the default),
+ * the highest {@link FacetRequest#numResults} weighted categories will be
+ * returned, otherwise the lowest ones.
+ */
public enum SortOrder { ASCENDING, DESCENDING }
-
- /**
- * Default depth for facets accumulation.
- * @see #getDepth()
- */
- public static final int DEFAULT_DEPTH = 1;
-
- /**
- * Default result mode
- * @see #getResultMode()
- */
- public static final ResultMode DEFAULT_RESULT_MODE = ResultMode.PER_NODE_IN_TREE;
-
+
+ /** The category being aggregated in this facet request. */
public final CategoryPath categoryPath;
+
+ /** The number of child categories to return for {@link #categoryPath}. */
public final int numResults;
private int numLabel;
- private int depth;
- private SortOrder sortOrder;
+ private int depth = 1;
+ private SortOrder sortOrder = SortOrder.DESCENDING;
+ private ResultMode resultMode = ResultMode.PER_NODE_IN_TREE;
- /**
- * Computed at construction, this hashCode is based on two final members
- * {@link CategoryPath} and numResults
- */
+ // Computed at construction; based on categoryPath and numResults.
private final int hashCode;
- private ResultMode resultMode = DEFAULT_RESULT_MODE;
-
/**
- * Initialize the request with a given path, and a requested number of facets
- * results. By default, all returned results would be labeled - to alter this
- * default see {@link #setNumLabel(int)}.
- *
- * NOTE: if numResults
is given as
- * Integer.MAX_VALUE
than all the facet results would be
- * returned, without any limit.
- *
- * NOTE: it is assumed that the given {@link CategoryPath} is not
- * modified after construction of this object. Otherwise, some things may not
- * function properly, e.g. {@link #hashCode()}.
+ * Constructor with the given category to aggregate and the number of child
+ * categories to return.
*
- * @throws IllegalArgumentException if numResults is ≤ 0
+ * @param path
+ * the category to aggregate. Cannot be {@code null}.
+ * @param numResults
+ * the number of child categories to return. If set to
+ * {@code Integer.MAX_VALUE}, all immediate child categories will be
+ * returned. Must be greater than 0.
*/
public FacetRequest(CategoryPath path, int numResults) {
if (numResults <= 0) {
@@ -118,9 +116,6 @@ public abstract class FacetRequest {
categoryPath = path;
this.numResults = numResults;
numLabel = numResults;
- depth = DEFAULT_DEPTH;
- sortOrder = SortOrder.DESCENDING;
-
hashCode = categoryPath.hashCode() ^ this.numResults;
}
@@ -147,123 +142,125 @@ public abstract class FacetRequest {
@Override
public boolean equals(Object o) {
if (o instanceof FacetRequest) {
- FacetRequest that = (FacetRequest)o;
- return that.hashCode == this.hashCode &&
+ FacetRequest that = (FacetRequest) o;
+ return that.hashCode == this.hashCode &&
that.categoryPath.equals(this.categoryPath) &&
that.numResults == this.numResults &&
that.depth == this.depth &&
that.resultMode == this.resultMode &&
- that.numLabel == this.numLabel;
+ that.numLabel == this.numLabel &&
+ that.sortOrder == this.sortOrder;
}
return false;
}
/**
- * How deeply to look under the given category. If the depth is 0,
- * only the category itself is counted. If the depth is 1, its immediate
- * children are also counted, and so on. If the depth is Integer.MAX_VALUE,
- * all the category's descendants are counted.
+ * How deeply to look under {@link #categoryPath}. By default, only its
+ * immediate children are aggregated (depth=1). If set to
+ * {@code Integer.MAX_VALUE}, the entire sub-tree of the category will be
+ * aggregated.
+ *
+ * NOTE: setting depth to 0 means that only the category itself should + * be aggregated. In that case, make sure to index the category with + * {@link OrdinalPolicy#ALL_PARENTS}, unless it is not the root category (the + * dimension), in which case {@link OrdinalPolicy#ALL_BUT_DIMENSION} is fine + * too. */ public final int getDepth() { - // TODO add AUTO_EXPAND option + // TODO an AUTO_EXPAND option could be useful return depth; } /** - * Returns the {@link FacetArraysSource} this {@link FacetRequest} uses in + * Returns the {@link FacetArraysSource} this request uses in * {@link #getValueOf(FacetArrays, int)}. */ public abstract FacetArraysSource getFacetArraysSource(); /** - * If getNumLabel() < getNumResults(), only the first getNumLabel() results - * will have their category paths calculated, and the rest will only be - * available as ordinals (category numbers) and will have null paths. - *
- * If Integer.MAX_VALUE is specified, all results are labled. - *
- * The purpose of this parameter is to avoid having to run the whole faceted - * search again when the user asks for more values for the facet; The - * application can ask (getNumResults()) for more values than it needs to - * show, but keep getNumLabel() only the number it wants to immediately show. - * The slow-down caused by finding more values is negligible, because the - * slowest part - finding the categories' paths, is avoided. + * Allows to specify the number of categories to label. By default all + * returned categories are labeled. *
- * Depending on the {@link #getResultMode() LimitsMode}, this limit is applied
- * globally or per results node. In the global mode, if this limit is 3, only
- * 3 top results would be labeled. In the per-node mode, if this limit is 3, 3
- * top children of {@link #categoryPath the target category} would be labeled,
- * as well as 3 top children of each of them, and so forth, until the depth
- * defined by {@link #getDepth()}.
- *
- * @see #getResultMode()
+ * This allows an app to request a large number of results to return, while
+ * labeling them on-demand (e.g. when the UI requests to show more
+ * categories).
*/
public final int getNumLabel() {
return numLabel;
}
- /** Return the requested result mode. */
+ /** Return the requested result mode (defaults to {@link ResultMode#PER_NODE_IN_TREE}. */
public final ResultMode getResultMode() {
return resultMode;
}
- /** Return the requested order of results. */
+ /** Return the requested order of results (defaults to {@link SortOrder#DESCENDING}. */
public final SortOrder getSortOrder() {
return sortOrder;
}
/**
- * Return the value of a category used for facets computations for this
- * request. For a count request this would be the count for that facet, i.e.
- * an integer number. but for other requests this can be the result of a more
- * complex operation, and the result can be any double precision number.
- * Having this method with a general name value which is double
- * precision allows to have more compact API and code for handling counts and
- * perhaps other requests (such as for associations) very similarly, and by
- * the same code and API, avoiding code duplication.
+ * Return the weight of the requested category ordinal. A {@link FacetRequest}
+ * is responsible for resolving the weight of a category given the
+ * {@link FacetArrays} and {@link #getFacetArraysSource()}. E.g. a counting
+ * request will probably return the value of the category from
+ * {@link FacetArrays#getIntArray()} while an average-weighting request will
+ * compute the value using both arrays.
*
* @param arrays
- * provider for facet arrays in use for current computation.
- * @param idx
- * an index into the count arrays now in effect in
- * arrays
. E.g., for ordinal number n, with
- * partition, of size partitionSize, now covering n,
- * getValueOf
would be invoked with idx
- * being n % partitionSize.
+ * the arrays used to aggregate the categories weights.
+ * @param ordinal
+ * the category ordinal for which to return the weight.
*/
// TODO perhaps instead of getValueOf we can have a postProcess(FacetArrays)
// That, together with getFacetArraysSource should allow ResultHandlers to
// efficiently obtain the values from the arrays directly
- public abstract double getValueOf(FacetArrays arrays, int idx);
+ public abstract double getValueOf(FacetArrays arrays, int ordinal);
@Override
public int hashCode() {
return hashCode;
}
+ /**
+ * Sets the depth up to which to aggregate facets.
+ *
+ * @see #getDepth()
+ */
public void setDepth(int depth) {
this.depth = depth;
}
+ /**
+ * Sets the number of categories to label.
+ *
+ * @see #getNumLabel()
+ */
public void setNumLabel(int numLabel) {
this.numLabel = numLabel;
}
/**
- * @param resultMode the resultMode to set
+ * Sets the {@link ResultMode} for this request.
+ *
* @see #getResultMode()
*/
public void setResultMode(ResultMode resultMode) {
this.resultMode = resultMode;
}
-
+
+ /**
+ * Sets the {@link SortOrder} for this request.
+ *
+ * @see #getSortOrder()
+ */
public void setSortOrder(SortOrder sortOrder) {
this.sortOrder = sortOrder;
}
@Override
public String toString() {
- return categoryPath.toString()+" nRes="+numResults+" nLbl="+numLabel;
+ return categoryPath.toString() + " nRes=" + numResults + " nLbl=" + numLabel;
}
}