mirror of https://github.com/apache/lucene.git
SOLR-1240: Added support for generalized Numerical Range faceting on any numeric (or date) field. Note: this required modifying ConvertedLegacyTest to deal with an expectation about how many fields a specific document has (there are more now because of a copyField i added to the schema)
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@980555 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
d5ded69e49
commit
adaeb656c8
|
@ -214,6 +214,11 @@ New Features
|
||||||
* SOLR-1925: Add CSVResponseWriter (use wt=csv) that returns the list of documents
|
* SOLR-1925: Add CSVResponseWriter (use wt=csv) that returns the list of documents
|
||||||
in CSV format. (Chris Mattmann, yonik)
|
in CSV format. (Chris Mattmann, yonik)
|
||||||
|
|
||||||
|
* SOLR-1240: "Rnage Faceting has been added. This is a generalization
|
||||||
|
of the existing "Date Faceting" logic so that it now supports any
|
||||||
|
all stock numeric field types that support range queries in addition
|
||||||
|
to dates.
|
||||||
|
(Gijs Kunze, hossman)
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -153,36 +153,10 @@ public interface FacetParams {
|
||||||
* String indicating what "other" ranges should be computed for a
|
* String indicating what "other" ranges should be computed for a
|
||||||
* date facet range (multi-value).
|
* date facet range (multi-value).
|
||||||
* Can be overriden on a per field basis.
|
* Can be overriden on a per field basis.
|
||||||
* @see FacetDateOther
|
* @see FacetRangeOther
|
||||||
*/
|
*/
|
||||||
public static final String FACET_DATE_OTHER = FACET_DATE + ".other";
|
public static final String FACET_DATE_OTHER = FACET_DATE + ".other";
|
||||||
|
|
||||||
/**
|
|
||||||
* An enumeration of the legal values for FACET_DATE_OTHER...
|
|
||||||
* <ul>
|
|
||||||
* <li>before = the count of matches before the start date</li>
|
|
||||||
* <li>after = the count of matches after the end date</li>
|
|
||||||
* <li>between = the count of all matches between start and end</li>
|
|
||||||
* <li>all = all of the above (default value)</li>
|
|
||||||
* <li>none = no additional info requested</li>
|
|
||||||
* </ul>
|
|
||||||
* @see #FACET_DATE_OTHER
|
|
||||||
* @see #FACET_DATE_INCLUDE
|
|
||||||
*/
|
|
||||||
public enum FacetDateOther {
|
|
||||||
BEFORE, AFTER, BETWEEN, ALL, NONE;
|
|
||||||
public String toString() { return super.toString().toLowerCase(Locale.ENGLISH); }
|
|
||||||
public static FacetDateOther get(String label) {
|
|
||||||
try {
|
|
||||||
return valueOf(label.toUpperCase(Locale.ENGLISH));
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
throw new SolrException
|
|
||||||
(SolrException.ErrorCode.BAD_REQUEST,
|
|
||||||
label+" is not a valid type of 'other' date facet information",e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Multivalued string indicating what rules should be applied to determine
|
* Multivalued string indicating what rules should be applied to determine
|
||||||
|
@ -195,12 +169,124 @@ public interface FacetParams {
|
||||||
* <p>
|
* <p>
|
||||||
* Can be overriden on a per field basis.
|
* Can be overriden on a per field basis.
|
||||||
* </p>
|
* </p>
|
||||||
* @see FacetDateInclude
|
* @see FacetRangeInclude
|
||||||
*/
|
*/
|
||||||
public static final String FACET_DATE_INCLUDE = FACET_DATE + ".include";
|
public static final String FACET_DATE_INCLUDE = FACET_DATE + ".include";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enumeration of the legal values for FACET_DATE_INCLUDE...
|
* Any numerical field whose terms the user wants to enumerate over
|
||||||
|
* Facet Contraint Counts for selected ranges.
|
||||||
|
*/
|
||||||
|
public static final String FACET_RANGE = FACET + ".range";
|
||||||
|
/**
|
||||||
|
* Number indicating the starting point for a numerical range facet.
|
||||||
|
* Can be overriden on a per field basis.
|
||||||
|
*/
|
||||||
|
public static final String FACET_RANGE_START = FACET_RANGE + ".start";
|
||||||
|
/**
|
||||||
|
* Number indicating the ending point for a numerical range facet.
|
||||||
|
* Can be overriden on a per field basis.
|
||||||
|
*/
|
||||||
|
public static final String FACET_RANGE_END = FACET_RANGE + ".end";
|
||||||
|
/**
|
||||||
|
* Number indicating the interval of sub-ranges for a numerical
|
||||||
|
* facet range.
|
||||||
|
* Can be overriden on a per field basis.
|
||||||
|
*/
|
||||||
|
public static final String FACET_RANGE_GAP = FACET_RANGE + ".gap";
|
||||||
|
/**
|
||||||
|
* Boolean indicating how counts should be computed if the range
|
||||||
|
* between 'start' and 'end' is not evenly divisible by 'gap'. If
|
||||||
|
* this value is true, then all counts of ranges involving the 'end'
|
||||||
|
* point will use the exact endpoint specified -- this includes the
|
||||||
|
* 'between' and 'after' counts as well as the last range computed
|
||||||
|
* using the 'gap'. If the value is false, then 'gap' is used to
|
||||||
|
* compute the effective endpoint closest to the 'end' param which
|
||||||
|
* results in the range between 'start' and 'end' being evenly
|
||||||
|
* divisible by 'gap'.
|
||||||
|
* The default is false.
|
||||||
|
* Can be overriden on a per field basis.
|
||||||
|
*/
|
||||||
|
public static final String FACET_RANGE_HARD_END = FACET_RANGE + ".hardend";
|
||||||
|
/**
|
||||||
|
* String indicating what "other" ranges should be computed for a
|
||||||
|
* numerical range facet (multi-value).
|
||||||
|
* Can be overriden on a per field basis.
|
||||||
|
* @see FacetNumberOther
|
||||||
|
*/
|
||||||
|
public static final String FACET_RANGE_OTHER = FACET_RANGE + ".other";
|
||||||
|
/**
|
||||||
|
* String indicating whether ranges for numerical range faceting
|
||||||
|
* should be exclusive or inclusive. By default both the start and
|
||||||
|
* end point are inclusive.
|
||||||
|
* Can be overriden on a per field basis.
|
||||||
|
* @see FacetNumberExclusive
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Multivalued string indicating what rules should be applied to determine
|
||||||
|
* when the the ranges generated for numeric faceting should be inclusive or
|
||||||
|
* exclusive of their end points.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The default value if none are specified is: [lower,upper,edge]
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Can be overriden on a per field basis.
|
||||||
|
* </p>
|
||||||
|
* @see FacetRangeInclude
|
||||||
|
*/
|
||||||
|
public static final String FACET_RANGE_INCLUDE = FACET_RANGE + ".include";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enumeration of the legal values for {@link #FACET_RANGE_OTHER} and {@link #FACET_DATE_OTHER} ...
|
||||||
|
* <ul>
|
||||||
|
* <li>before = the count of matches before the start</li>
|
||||||
|
* <li>after = the count of matches after the end</li>
|
||||||
|
* <li>between = the count of all matches between start and end</li>
|
||||||
|
* <li>all = all of the above (default value)</li>
|
||||||
|
* <li>none = no additional info requested</li>
|
||||||
|
* </ul>
|
||||||
|
* @see #FACET_RANGE_OTHER
|
||||||
|
* @see #FACET_DATE_OTHER
|
||||||
|
*/
|
||||||
|
public enum FacetRangeOther {
|
||||||
|
BEFORE, AFTER, BETWEEN, ALL, NONE;
|
||||||
|
public String toString() { return super.toString().toLowerCase(); }
|
||||||
|
public static FacetRangeOther get(String label) {
|
||||||
|
try {
|
||||||
|
return valueOf(label.toUpperCase());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new SolrException
|
||||||
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
label+" is not a valid type of 'other' range facet information",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link FacetRangeOther}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public enum FacetDateOther {
|
||||||
|
BEFORE, AFTER, BETWEEN, ALL, NONE;
|
||||||
|
public String toString() { return super.toString().toLowerCase(); }
|
||||||
|
public static FacetDateOther get(String label) {
|
||||||
|
try {
|
||||||
|
return valueOf(label.toUpperCase());
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new SolrException
|
||||||
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
label+" is not a valid type of 'other' range facet information",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enumeration of the legal values for {@link #FACET_DATE_INCLUDE} and {@link #FACET_RANGE_INCLUDE}
|
||||||
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>lower = all gap based ranges include their lower bound</li>
|
* <li>lower = all gap based ranges include their lower bound</li>
|
||||||
* <li>upper = all gap based ranges include their upper bound</li>
|
* <li>upper = all gap based ranges include their upper bound</li>
|
||||||
|
@ -208,43 +294,45 @@ public interface FacetParams {
|
||||||
* for the first one, upper for the last one) even if the corresponding
|
* for the first one, upper for the last one) even if the corresponding
|
||||||
* upper/lower option is not specified
|
* upper/lower option is not specified
|
||||||
* </li>
|
* </li>
|
||||||
* <li>outer = the FacetDateOther.BEFORE and FacetDateOther.AFTER ranges
|
* <li>outer = the BEFORE and AFTER ranges
|
||||||
* should be inclusive of their bounds, even if the first or last ranges
|
* should be inclusive of their bounds, even if the first or last ranges
|
||||||
* already include those boundaries.
|
* already include those boundaries.
|
||||||
* </li>
|
* </li>
|
||||||
* <li>all = shorthand for lower, upper, edge, and outer</li>
|
* <li>all = shorthand for lower, upper, edge, and outer</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* @see #FACET_DATE_INCLUDE
|
* @see #FACET_DATE_INCLUDE
|
||||||
|
* @see #FACET_RANGE_INCLUDE
|
||||||
*/
|
*/
|
||||||
public enum FacetDateInclude {
|
public enum FacetRangeInclude {
|
||||||
ALL, LOWER, UPPER, EDGE, OUTER;
|
ALL, LOWER, UPPER, EDGE, OUTER;
|
||||||
public String toString() { return super.toString().toLowerCase(Locale.ENGLISH); }
|
public String toString() { return super.toString().toLowerCase(Locale.ENGLISH); }
|
||||||
public static FacetDateInclude get(String label) {
|
public static FacetRangeInclude get(String label) {
|
||||||
try {
|
try {
|
||||||
return valueOf(label.toUpperCase(Locale.ENGLISH));
|
return valueOf(label.toUpperCase(Locale.ENGLISH));
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new SolrException
|
throw new SolrException
|
||||||
(SolrException.ErrorCode.BAD_REQUEST,
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
label+" is not a valid type of for "+FACET_DATE_INCLUDE+" information",e);
|
label+" is not a valid type of for range 'include' information",e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Convinience method for parsing the param value according to the correct semantics.
|
* Convinience method for parsing the param value according to the
|
||||||
|
* correct semantics.
|
||||||
*/
|
*/
|
||||||
public static EnumSet<FacetDateInclude> parseParam(final String[] param) {
|
public static EnumSet<FacetRangeInclude> parseParam(final String[] param) {
|
||||||
// short circut for default behavior
|
// short circut for default behavior
|
||||||
if (null == param || 0 == param.length )
|
if (null == param || 0 == param.length )
|
||||||
return EnumSet.of(LOWER, UPPER, EDGE);
|
return EnumSet.of(LOWER, UPPER, EDGE);
|
||||||
|
|
||||||
// build up set containing whatever is specified
|
// build up set containing whatever is specified
|
||||||
final EnumSet<FacetDateInclude> include = EnumSet.noneOf(FacetDateInclude.class);
|
final EnumSet<FacetRangeInclude> include = EnumSet.noneOf(FacetRangeInclude.class);
|
||||||
for (final String o : param) {
|
for (final String o : param) {
|
||||||
include.add(FacetDateInclude.get(o));
|
include.add(FacetRangeInclude.get(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if set contains all, then we're back to short circuting
|
// if set contains all, then we're back to short circuting
|
||||||
if (include.contains(FacetDateInclude.ALL))
|
if (include.contains(FacetRangeInclude.ALL))
|
||||||
return EnumSet.allOf(FacetDateInclude.class);
|
return EnumSet.allOf(FacetRangeInclude.class);
|
||||||
|
|
||||||
// use whatever we've got.
|
// use whatever we've got.
|
||||||
return include;
|
return include;
|
||||||
|
|
|
@ -404,8 +404,9 @@ public class FacetComponent extends SearchComponent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: facet dates
|
// TODO: facet dates & numbers
|
||||||
facet_counts.add("facet_dates", new SimpleOrderedMap());
|
facet_counts.add("facet_dates", new SimpleOrderedMap());
|
||||||
|
facet_counts.add("facet_ranges", new SimpleOrderedMap());
|
||||||
|
|
||||||
rb.rsp.add("facet_counts", facet_counts);
|
rb.rsp.add("facet_counts", facet_counts);
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,14 @@ import org.apache.solr.common.params.FacetParams;
|
||||||
import org.apache.solr.common.params.RequiredSolrParams;
|
import org.apache.solr.common.params.RequiredSolrParams;
|
||||||
import org.apache.solr.common.params.SolrParams;
|
import org.apache.solr.common.params.SolrParams;
|
||||||
import org.apache.solr.common.params.CommonParams;
|
import org.apache.solr.common.params.CommonParams;
|
||||||
import org.apache.solr.common.params.FacetParams.FacetDateOther;
|
import org.apache.solr.common.params.FacetParams.FacetRangeOther;
|
||||||
import org.apache.solr.common.params.FacetParams.FacetDateInclude;
|
import org.apache.solr.common.params.FacetParams.FacetRangeInclude;
|
||||||
import org.apache.solr.common.util.NamedList;
|
import org.apache.solr.common.util.NamedList;
|
||||||
import org.apache.solr.common.util.SimpleOrderedMap;
|
import org.apache.solr.common.util.SimpleOrderedMap;
|
||||||
import org.apache.solr.common.util.StrUtils;
|
import org.apache.solr.common.util.StrUtils;
|
||||||
import org.apache.solr.core.SolrCore;
|
import org.apache.solr.core.SolrCore;
|
||||||
import org.apache.solr.schema.*;
|
import org.apache.solr.schema.*;
|
||||||
|
import org.apache.solr.schema.TrieField.TrieTypes;
|
||||||
import org.apache.solr.search.*;
|
import org.apache.solr.search.*;
|
||||||
import org.apache.solr.util.BoundedTreeSet;
|
import org.apache.solr.util.BoundedTreeSet;
|
||||||
import org.apache.solr.util.ByteUtils;
|
import org.apache.solr.util.ByteUtils;
|
||||||
|
@ -63,11 +64,14 @@ public class SimpleFacets {
|
||||||
protected DocSet docs;
|
protected DocSet docs;
|
||||||
/** Configuration params behavior should be driven by */
|
/** Configuration params behavior should be driven by */
|
||||||
protected SolrParams params;
|
protected SolrParams params;
|
||||||
|
protected SolrParams required;
|
||||||
/** Searcher to use for all calculations */
|
/** Searcher to use for all calculations */
|
||||||
protected SolrIndexSearcher searcher;
|
protected SolrIndexSearcher searcher;
|
||||||
protected SolrQueryRequest req;
|
protected SolrQueryRequest req;
|
||||||
protected ResponseBuilder rb;
|
protected ResponseBuilder rb;
|
||||||
|
|
||||||
|
public final Date NOW = new Date();
|
||||||
|
|
||||||
// per-facet values
|
// per-facet values
|
||||||
SolrParams localParams; // localParams on this particular facet command
|
SolrParams localParams; // localParams on this particular facet command
|
||||||
String facetValue; // the field to or query to facet on (minus local params)
|
String facetValue; // the field to or query to facet on (minus local params)
|
||||||
|
@ -89,6 +93,7 @@ public class SimpleFacets {
|
||||||
this.searcher = req.getSearcher();
|
this.searcher = req.getSearcher();
|
||||||
this.base = this.docs = docs;
|
this.base = this.docs = docs;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
|
this.required = new RequiredSolrParams(params);
|
||||||
this.rb = rb;
|
this.rb = rb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +171,7 @@ public class SimpleFacets {
|
||||||
* @see #getFacetQueryCounts
|
* @see #getFacetQueryCounts
|
||||||
* @see #getFacetFieldCounts
|
* @see #getFacetFieldCounts
|
||||||
* @see #getFacetDateCounts
|
* @see #getFacetDateCounts
|
||||||
|
* @see #getFacetRangeCounts
|
||||||
* @see FacetParams#FACET
|
* @see FacetParams#FACET
|
||||||
* @return a NamedList of Facet Count info or null
|
* @return a NamedList of Facet Count info or null
|
||||||
*/
|
*/
|
||||||
|
@ -181,6 +187,7 @@ public class SimpleFacets {
|
||||||
res.add("facet_queries", getFacetQueryCounts());
|
res.add("facet_queries", getFacetQueryCounts());
|
||||||
res.add("facet_fields", getFacetFieldCounts());
|
res.add("facet_fields", getFacetFieldCounts());
|
||||||
res.add("facet_dates", getFacetDateCounts());
|
res.add("facet_dates", getFacetDateCounts());
|
||||||
|
res.add("facet_ranges", getFacetRangeCounts());
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SolrException.logOnce(SolrCore.log, "Exception during facet counts", e);
|
SolrException.logOnce(SolrCore.log, "Exception during facet counts", e);
|
||||||
|
@ -725,10 +732,8 @@ public class SimpleFacets {
|
||||||
public NamedList getFacetDateCounts()
|
public NamedList getFacetDateCounts()
|
||||||
throws IOException, ParseException {
|
throws IOException, ParseException {
|
||||||
|
|
||||||
final SolrParams required = new RequiredSolrParams(params);
|
|
||||||
final NamedList resOuter = new SimpleOrderedMap();
|
final NamedList resOuter = new SimpleOrderedMap();
|
||||||
final String[] fields = params.getParams(FacetParams.FACET_DATE);
|
final String[] fields = params.getParams(FacetParams.FACET_DATE);
|
||||||
final Date NOW = new Date();
|
|
||||||
|
|
||||||
if (null == fields || 0 == fields.length) return resOuter;
|
if (null == fields || 0 == fields.length) return resOuter;
|
||||||
|
|
||||||
|
@ -778,9 +783,9 @@ public class SimpleFacets {
|
||||||
final DateMathParser dmp = new DateMathParser(ft.UTC, Locale.US);
|
final DateMathParser dmp = new DateMathParser(ft.UTC, Locale.US);
|
||||||
dmp.setNow(NOW);
|
dmp.setNow(NOW);
|
||||||
|
|
||||||
int minCount = params.getFieldInt(f,FacetParams.FACET_MINCOUNT, 0);
|
final int minCount = params.getFieldInt(f,FacetParams.FACET_MINCOUNT, 0);
|
||||||
|
|
||||||
final EnumSet<FacetDateInclude> include = FacetDateInclude.parseParam
|
final EnumSet<FacetRangeInclude> include = FacetRangeInclude.parseParam
|
||||||
(params.getFieldParams(f,FacetParams.FACET_DATE_INCLUDE));
|
(params.getFieldParams(f,FacetParams.FACET_DATE_INCLUDE));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -802,14 +807,14 @@ public class SimpleFacets {
|
||||||
(SolrException.ErrorCode.BAD_REQUEST,
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
"date facet infinite loop (is gap negative?)");
|
"date facet infinite loop (is gap negative?)");
|
||||||
}
|
}
|
||||||
boolean includeLower =
|
final boolean includeLower =
|
||||||
(include.contains(FacetDateInclude.LOWER) ||
|
(include.contains(FacetRangeInclude.LOWER) ||
|
||||||
(include.contains(FacetDateInclude.EDGE) && low.equals(start)));
|
(include.contains(FacetRangeInclude.EDGE) && low.equals(start)));
|
||||||
boolean includeUpper =
|
final boolean includeUpper =
|
||||||
(include.contains(FacetDateInclude.UPPER) ||
|
(include.contains(FacetRangeInclude.UPPER) ||
|
||||||
(include.contains(FacetDateInclude.EDGE) && high.equals(end)));
|
(include.contains(FacetRangeInclude.EDGE) && high.equals(end)));
|
||||||
|
|
||||||
int count = rangeCount(sf,low,high,includeLower,includeUpper);
|
final int count = rangeCount(sf,low,high,includeLower,includeUpper);
|
||||||
if (count >= minCount) {
|
if (count >= minCount) {
|
||||||
resInner.add(label, count);
|
resInner.add(label, count);
|
||||||
}
|
}
|
||||||
|
@ -821,49 +826,52 @@ public class SimpleFacets {
|
||||||
"date facet 'gap' is not a valid Date Math string: " + gap, e);
|
"date facet 'gap' is not a valid Date Math string: " + gap, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicitly return the gap and end so all the counts are meaningful
|
// explicitly return the gap and end so all the counts
|
||||||
|
// (including before/after/between) are meaningful - even if mincount
|
||||||
|
// has removed the neighboring ranges
|
||||||
resInner.add("gap", gap);
|
resInner.add("gap", gap);
|
||||||
|
resInner.add("start", start);
|
||||||
resInner.add("end", end);
|
resInner.add("end", end);
|
||||||
|
|
||||||
final String[] othersP =
|
final String[] othersP =
|
||||||
params.getFieldParams(f,FacetParams.FACET_DATE_OTHER);
|
params.getFieldParams(f,FacetParams.FACET_DATE_OTHER);
|
||||||
if (null != othersP && 0 < othersP.length ) {
|
if (null != othersP && 0 < othersP.length ) {
|
||||||
Set<FacetDateOther> others = EnumSet.noneOf(FacetDateOther.class);
|
final Set<FacetRangeOther> others = EnumSet.noneOf(FacetRangeOther.class);
|
||||||
|
|
||||||
for (final String o : othersP) {
|
for (final String o : othersP) {
|
||||||
others.add(FacetDateOther.get(o));
|
others.add(FacetRangeOther.get(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
// no matter what other values are listed, we don't do
|
// no matter what other values are listed, we don't do
|
||||||
// anything if "none" is specified.
|
// anything if "none" is specified.
|
||||||
if (! others.contains(FacetDateOther.NONE) ) {
|
if (! others.contains(FacetRangeOther.NONE) ) {
|
||||||
boolean all = others.contains(FacetDateOther.ALL);
|
boolean all = others.contains(FacetRangeOther.ALL);
|
||||||
|
|
||||||
if (all || others.contains(FacetDateOther.BEFORE)) {
|
if (all || others.contains(FacetRangeOther.BEFORE)) {
|
||||||
// include upper bound if "outer" or if first gap doesn't already include it
|
// include upper bound if "outer" or if first gap doesn't already include it
|
||||||
resInner.add(FacetDateOther.BEFORE.toString(),
|
resInner.add(FacetRangeOther.BEFORE.toString(),
|
||||||
rangeCount(sf,null,start,
|
rangeCount(sf,null,start,
|
||||||
false,
|
false,
|
||||||
(include.contains(FacetDateInclude.OUTER) ||
|
(include.contains(FacetRangeInclude.OUTER) ||
|
||||||
(! (include.contains(FacetDateInclude.LOWER) ||
|
(! (include.contains(FacetRangeInclude.LOWER) ||
|
||||||
include.contains(FacetDateInclude.EDGE))))));
|
include.contains(FacetRangeInclude.EDGE))))));
|
||||||
}
|
}
|
||||||
if (all || others.contains(FacetDateOther.AFTER)) {
|
if (all || others.contains(FacetRangeOther.AFTER)) {
|
||||||
// include lower bound if "outer" or if last gap doesn't already include it
|
// include lower bound if "outer" or if last gap doesn't already include it
|
||||||
resInner.add(FacetDateOther.AFTER.toString(),
|
resInner.add(FacetRangeOther.AFTER.toString(),
|
||||||
rangeCount(sf,end,null,
|
rangeCount(sf,end,null,
|
||||||
(include.contains(FacetDateInclude.OUTER) ||
|
(include.contains(FacetRangeInclude.OUTER) ||
|
||||||
(! (include.contains(FacetDateInclude.UPPER) ||
|
(! (include.contains(FacetRangeInclude.UPPER) ||
|
||||||
include.contains(FacetDateInclude.EDGE)))),
|
include.contains(FacetRangeInclude.EDGE)))),
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
if (all || others.contains(FacetDateOther.BETWEEN)) {
|
if (all || others.contains(FacetRangeOther.BETWEEN)) {
|
||||||
resInner.add(FacetDateOther.BETWEEN.toString(),
|
resInner.add(FacetRangeOther.BETWEEN.toString(),
|
||||||
rangeCount(sf,start,end,
|
rangeCount(sf,start,end,
|
||||||
(include.contains(FacetDateInclude.LOWER) ||
|
(include.contains(FacetRangeInclude.LOWER) ||
|
||||||
include.contains(FacetDateInclude.EDGE)),
|
include.contains(FacetRangeInclude.EDGE)),
|
||||||
(include.contains(FacetDateInclude.UPPER) ||
|
(include.contains(FacetRangeInclude.UPPER) ||
|
||||||
include.contains(FacetDateInclude.EDGE))));
|
include.contains(FacetRangeInclude.EDGE))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -872,6 +880,197 @@ public class SimpleFacets {
|
||||||
return resOuter;
|
return resOuter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of value constraints and the associated facet
|
||||||
|
* counts for each facet numerical field, range, and interval
|
||||||
|
* specified in the SolrParams
|
||||||
|
*
|
||||||
|
* @see FacetParams#FACET_RANGE
|
||||||
|
*/
|
||||||
|
public NamedList getFacetRangeCounts()
|
||||||
|
throws IOException, ParseException {
|
||||||
|
|
||||||
|
final NamedList resOuter = new SimpleOrderedMap();
|
||||||
|
final String[] fields = params.getParams(FacetParams.FACET_RANGE);
|
||||||
|
|
||||||
|
if (null == fields || 0 == fields.length) return resOuter;
|
||||||
|
|
||||||
|
final IndexSchema schema = searcher.getSchema();
|
||||||
|
for (String f : fields) {
|
||||||
|
parseParams(FacetParams.FACET_RANGE, f);
|
||||||
|
f = facetValue;
|
||||||
|
|
||||||
|
final SchemaField sf = schema.getField(f);
|
||||||
|
final FieldType ft = sf.getType();
|
||||||
|
|
||||||
|
RangeEndpointCalculator calc = null;
|
||||||
|
|
||||||
|
if (ft instanceof TrieField) {
|
||||||
|
final TrieField trie = (TrieField)ft;
|
||||||
|
|
||||||
|
switch (trie.getType()) {
|
||||||
|
case FLOAT:
|
||||||
|
calc = new FloatRangeEndpointCalculator(sf);
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
calc = new DoubleRangeEndpointCalculator(sf);
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
calc = new IntegerRangeEndpointCalculator(sf);
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
calc = new LongRangeEndpointCalculator(sf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new SolrException
|
||||||
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
"Unable to range facet on tried field of unexpected type:" + f);
|
||||||
|
}
|
||||||
|
} else if (ft instanceof DateField) {
|
||||||
|
calc = new DateRangeEndpointCalculator(sf, NOW);
|
||||||
|
} else if (ft instanceof SortableIntField) {
|
||||||
|
calc = new IntegerRangeEndpointCalculator(sf);
|
||||||
|
} else if (ft instanceof SortableLongField) {
|
||||||
|
calc = new LongRangeEndpointCalculator(sf);
|
||||||
|
} else if (ft instanceof SortableFloatField) {
|
||||||
|
calc = new FloatRangeEndpointCalculator(sf);
|
||||||
|
} else if (ft instanceof SortableDoubleField) {
|
||||||
|
calc = new DoubleRangeEndpointCalculator(sf);
|
||||||
|
} else {
|
||||||
|
throw new SolrException
|
||||||
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
"Unable to range facet on field:" + sf);
|
||||||
|
}
|
||||||
|
|
||||||
|
resOuter.add(key, getFacetRangeCounts(sf, calc));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resOuter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Comparable<T>> NamedList getFacetRangeCounts
|
||||||
|
(final SchemaField sf,
|
||||||
|
final RangeEndpointCalculator<T> calc) throws IOException {
|
||||||
|
|
||||||
|
final String f = sf.getName();
|
||||||
|
final NamedList res = new SimpleOrderedMap();
|
||||||
|
final NamedList counts = new SimpleOrderedMap();
|
||||||
|
res.add("counts", counts);
|
||||||
|
|
||||||
|
final T start = calc.getValue(required.getFieldParam(f,FacetParams.FACET_RANGE_START));
|
||||||
|
// not final, hardend may change this
|
||||||
|
T end = calc.getValue(required.getFieldParam(f,FacetParams.FACET_RANGE_END));
|
||||||
|
if (end.compareTo(start) < 0) {
|
||||||
|
throw new SolrException
|
||||||
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
"range facet 'end' comes before 'start': "+end+" < "+start);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String gap = required.getFieldParam(f, FacetParams.FACET_RANGE_GAP);
|
||||||
|
// explicitly return the gap. compute this early so we are more
|
||||||
|
// likely to catch parse errors before attempting math
|
||||||
|
res.add("gap", calc.getGap(gap));
|
||||||
|
|
||||||
|
final int minCount = params.getFieldInt(f,FacetParams.FACET_MINCOUNT, 0);
|
||||||
|
|
||||||
|
final EnumSet<FacetRangeInclude> include = FacetRangeInclude.parseParam
|
||||||
|
(params.getFieldParams(f,FacetParams.FACET_RANGE_INCLUDE));
|
||||||
|
|
||||||
|
T low = start;
|
||||||
|
|
||||||
|
while (low.compareTo(end) < 0) {
|
||||||
|
T high = calc.addGap(low, gap);
|
||||||
|
if (end.compareTo(high) < 0) {
|
||||||
|
if (params.getFieldBool(f,FacetParams.FACET_RANGE_HARD_END,false)) {
|
||||||
|
high = end;
|
||||||
|
} else {
|
||||||
|
end = high;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (high.compareTo(low) < 0) {
|
||||||
|
throw new SolrException
|
||||||
|
(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
"range facet infinite loop (is gap negative? did the math overflow?)");
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean includeLower =
|
||||||
|
(include.contains(FacetRangeInclude.LOWER) ||
|
||||||
|
(include.contains(FacetRangeInclude.EDGE) &&
|
||||||
|
0 == low.compareTo(start)));
|
||||||
|
final boolean includeUpper =
|
||||||
|
(include.contains(FacetRangeInclude.UPPER) ||
|
||||||
|
(include.contains(FacetRangeInclude.EDGE) &&
|
||||||
|
0 == high.compareTo(end)));
|
||||||
|
|
||||||
|
final String lowS = calc.formatValue(low);
|
||||||
|
final String highS = calc.formatValue(high);
|
||||||
|
|
||||||
|
final int count = rangeCount(sf, lowS, highS,
|
||||||
|
includeLower,includeUpper);
|
||||||
|
if (count >= minCount) {
|
||||||
|
counts.add(lowS, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
low = high;
|
||||||
|
}
|
||||||
|
|
||||||
|
// explicitly return the start and end so all the counts
|
||||||
|
// (including before/after/between) are meaningful - even if mincount
|
||||||
|
// has removed the neighboring ranges
|
||||||
|
res.add("start", start);
|
||||||
|
res.add("end", end);
|
||||||
|
|
||||||
|
final String[] othersP =
|
||||||
|
params.getFieldParams(f,FacetParams.FACET_RANGE_OTHER);
|
||||||
|
if (null != othersP && 0 < othersP.length ) {
|
||||||
|
Set<FacetRangeOther> others = EnumSet.noneOf(FacetRangeOther.class);
|
||||||
|
|
||||||
|
for (final String o : othersP) {
|
||||||
|
others.add(FacetRangeOther.get(o));
|
||||||
|
}
|
||||||
|
|
||||||
|
// no matter what other values are listed, we don't do
|
||||||
|
// anything if "none" is specified.
|
||||||
|
if (! others.contains(FacetRangeOther.NONE) ) {
|
||||||
|
|
||||||
|
boolean all = others.contains(FacetRangeOther.ALL);
|
||||||
|
final String startS = calc.formatValue(start);
|
||||||
|
final String endS = calc.formatValue(end);
|
||||||
|
|
||||||
|
if (all || others.contains(FacetRangeOther.BEFORE)) {
|
||||||
|
// include upper bound if "outer" or if first gap doesn't already include it
|
||||||
|
res.add(FacetRangeOther.BEFORE.toString(),
|
||||||
|
rangeCount(sf,null,startS,
|
||||||
|
false,
|
||||||
|
(include.contains(FacetRangeInclude.OUTER) ||
|
||||||
|
(! (include.contains(FacetRangeInclude.LOWER) ||
|
||||||
|
include.contains(FacetRangeInclude.EDGE))))));
|
||||||
|
|
||||||
|
}
|
||||||
|
if (all || others.contains(FacetRangeOther.AFTER)) {
|
||||||
|
// include lower bound if "outer" or if last gap doesn't already include it
|
||||||
|
res.add(FacetRangeOther.AFTER.toString(),
|
||||||
|
rangeCount(sf,endS,null,
|
||||||
|
(include.contains(FacetRangeInclude.OUTER) ||
|
||||||
|
(! (include.contains(FacetRangeInclude.UPPER) ||
|
||||||
|
include.contains(FacetRangeInclude.EDGE)))),
|
||||||
|
false));
|
||||||
|
}
|
||||||
|
if (all || others.contains(FacetRangeOther.BETWEEN)) {
|
||||||
|
res.add(FacetRangeOther.BETWEEN.toString(),
|
||||||
|
rangeCount(sf,startS,endS,
|
||||||
|
(include.contains(FacetRangeInclude.LOWER) ||
|
||||||
|
include.contains(FacetRangeInclude.EDGE)),
|
||||||
|
(include.contains(FacetRangeInclude.UPPER) ||
|
||||||
|
include.contains(FacetRangeInclude.EDGE))));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Macro for getting the numDocs of range over docs
|
* Macro for getting the numDocs of range over docs
|
||||||
* @see SolrIndexSearcher#numDocs
|
* @see SolrIndexSearcher#numDocs
|
||||||
|
@ -914,5 +1113,173 @@ public class SimpleFacets {
|
||||||
return (0 != vc ? vc : key.compareTo(o.key));
|
return (0 != vc ? vc : key.compareTo(o.key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perhaps someday instead of having a giant "instanceof" case
|
||||||
|
* statement to pick an impl, we can add a "RangeFacetable" marker
|
||||||
|
* interface to FieldTypes and they can return instances of these
|
||||||
|
* directly from some method -- but until then, keep this locked down
|
||||||
|
* and private.
|
||||||
|
*/
|
||||||
|
private static abstract class RangeEndpointCalculator<T extends Comparable<T>> {
|
||||||
|
protected final SchemaField field;
|
||||||
|
public RangeEndpointCalculator(final SchemaField field) {
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a Range endpoint for use as a range label name in the response.
|
||||||
|
* Default Impl just uses toString()
|
||||||
|
*/
|
||||||
|
public String formatValue(final T val) {
|
||||||
|
return val.toString();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Parses a String param into an Range endpoint value throwing
|
||||||
|
* a useful exception if not possible
|
||||||
|
*/
|
||||||
|
public final T getValue(final String rawval) {
|
||||||
|
try {
|
||||||
|
return parseVal(rawval);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
"Can't parse value "+rawval+" for field: " +
|
||||||
|
field.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Parses a String param into an Range endpoint.
|
||||||
|
* Can throw a low level format exception as needed.
|
||||||
|
*/
|
||||||
|
protected abstract T parseVal(final String rawval)
|
||||||
|
throws java.text.ParseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a String param into a value that represents the gap and
|
||||||
|
* can be included in the response, throwing
|
||||||
|
* a useful exception if not possible.
|
||||||
|
*
|
||||||
|
* Note: uses Object as the return type instead of T for things like
|
||||||
|
* Date where gap is just a DateMathParser string
|
||||||
|
*/
|
||||||
|
public final Object getGap(final String gap) {
|
||||||
|
try {
|
||||||
|
return parseGap(gap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
"Can't parse gap "+gap+" for field: " +
|
||||||
|
field.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a String param into a value that represents the gap and
|
||||||
|
* can be included in the response.
|
||||||
|
* Can throw a low level format exception as needed.
|
||||||
|
*
|
||||||
|
* Default Impl calls parseVal
|
||||||
|
*/
|
||||||
|
protected Object parseGap(final String rawval)
|
||||||
|
throws java.text.ParseException {
|
||||||
|
return parseVal(rawval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the String gap param to a low Range endpoint value to determine
|
||||||
|
* the corrisponding high Range endpoint value, throwing
|
||||||
|
* a useful exception if not possible.
|
||||||
|
*/
|
||||||
|
public final T addGap(T value, String gap) {
|
||||||
|
try {
|
||||||
|
return parseAndAddGap(value, gap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
|
||||||
|
"Can't add gap "+gap+" to value " + value +
|
||||||
|
" for field: " + field.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds the String gap param to a low Range endpoint value to determine
|
||||||
|
* the corrisponding high Range endpoint value.
|
||||||
|
* Can throw a low level format exception as needed.
|
||||||
|
*/
|
||||||
|
protected abstract T parseAndAddGap(T value, String gap)
|
||||||
|
throws java.text.ParseException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FloatRangeEndpointCalculator
|
||||||
|
extends RangeEndpointCalculator<Float> {
|
||||||
|
|
||||||
|
public FloatRangeEndpointCalculator(final SchemaField f) { super(f); }
|
||||||
|
protected Float parseVal(String rawval) {
|
||||||
|
return Float.valueOf(rawval);
|
||||||
|
}
|
||||||
|
public Float parseAndAddGap(Float value, String gap) {
|
||||||
|
return new Float(value.floatValue() + Float.valueOf(gap).floatValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static class DoubleRangeEndpointCalculator
|
||||||
|
extends RangeEndpointCalculator<Double> {
|
||||||
|
|
||||||
|
public DoubleRangeEndpointCalculator(final SchemaField f) { super(f); }
|
||||||
|
protected Double parseVal(String rawval) {
|
||||||
|
return Double.valueOf(rawval);
|
||||||
|
}
|
||||||
|
public Double parseAndAddGap(Double value, String gap) {
|
||||||
|
return new Double(value.floatValue() + Double.valueOf(gap).floatValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static class IntegerRangeEndpointCalculator
|
||||||
|
extends RangeEndpointCalculator<Integer> {
|
||||||
|
|
||||||
|
public IntegerRangeEndpointCalculator(final SchemaField f) { super(f); }
|
||||||
|
protected Integer parseVal(String rawval) {
|
||||||
|
return Integer.valueOf(rawval);
|
||||||
|
}
|
||||||
|
public Integer parseAndAddGap(Integer value, String gap) {
|
||||||
|
return new Integer(value.intValue() + Integer.valueOf(gap).intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static class LongRangeEndpointCalculator
|
||||||
|
extends RangeEndpointCalculator<Long> {
|
||||||
|
|
||||||
|
public LongRangeEndpointCalculator(final SchemaField f) { super(f); }
|
||||||
|
protected Long parseVal(String rawval) {
|
||||||
|
return Long.valueOf(rawval);
|
||||||
|
}
|
||||||
|
public Long parseAndAddGap(Long value, String gap) {
|
||||||
|
return new Long(value.intValue() + Long.valueOf(gap).intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static class DateRangeEndpointCalculator
|
||||||
|
extends RangeEndpointCalculator<Date> {
|
||||||
|
private final Date now;
|
||||||
|
public DateRangeEndpointCalculator(final SchemaField f,
|
||||||
|
final Date now) {
|
||||||
|
super(f);
|
||||||
|
this.now = now;
|
||||||
|
if (! (field.getType() instanceof DateField) ) {
|
||||||
|
throw new IllegalArgumentException
|
||||||
|
("SchemaField must use filed type extending DateField");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String formatValue(Date val) {
|
||||||
|
return ((DateField)field.getType()).toExternal(val);
|
||||||
|
}
|
||||||
|
protected Date parseVal(String rawval) {
|
||||||
|
return ((DateField)field.getType()).parseMath(now, rawval);
|
||||||
|
}
|
||||||
|
protected Object parseGap(final String rawval) {
|
||||||
|
return rawval;
|
||||||
|
}
|
||||||
|
public Date parseAndAddGap(Date value, String gap) throws java.text.ParseException {
|
||||||
|
final DateMathParser dmp = new DateMathParser(DateField.UTC, Locale.US);
|
||||||
|
dmp.setNow(value);
|
||||||
|
return dmp.parseMath(gap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1150,7 +1150,7 @@ public class ConvertedLegacyTest extends SolrTestCaseJ4 {
|
||||||
,"//str[.='Yonik'] "
|
,"//str[.='Yonik'] "
|
||||||
,"//float[.='1.4142135'] "
|
,"//float[.='1.4142135'] "
|
||||||
,"//float[@name='score'] "
|
,"//float[@name='score'] "
|
||||||
,"*[count(//doc/*)=13]"
|
,"*[count(//doc/*)>=13]"
|
||||||
);
|
);
|
||||||
args = new HashMap<String,String>();
|
args = new HashMap<String,String>();
|
||||||
args.put("version","2.0");
|
args.put("version","2.0");
|
||||||
|
@ -1161,7 +1161,7 @@ public class ConvertedLegacyTest extends SolrTestCaseJ4 {
|
||||||
,"//str[.='Yonik'] "
|
,"//str[.='Yonik'] "
|
||||||
,"//float[.='1.4142135'] "
|
,"//float[.='1.4142135'] "
|
||||||
,"//float[@name='score'] "
|
,"//float[@name='score'] "
|
||||||
,"*[count(//doc/*)=13]"
|
,"*[count(//doc/*)>=13]"
|
||||||
);
|
);
|
||||||
args = new HashMap<String,String>();
|
args = new HashMap<String,String>();
|
||||||
args.put("version","2.0");
|
args.put("version","2.0");
|
||||||
|
|
|
@ -72,17 +72,28 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void indexSimpleFacetCounts() {
|
static void indexSimpleFacetCounts() {
|
||||||
add_doc("id", "42", "trait_s", "Tool", "trait_s", "Obnoxious",
|
add_doc("id", "42",
|
||||||
|
"range_facet_f", "35.3",
|
||||||
|
"trait_s", "Tool", "trait_s", "Obnoxious",
|
||||||
"name", "Zapp Brannigan");
|
"name", "Zapp Brannigan");
|
||||||
add_doc("id", "43" ,
|
add_doc("id", "43" ,
|
||||||
|
"range_facet_f", "28.789",
|
||||||
"title", "Democratic Order of Planets");
|
"title", "Democratic Order of Planets");
|
||||||
add_doc("id", "44", "trait_s", "Tool",
|
add_doc("id", "44",
|
||||||
|
"range_facet_f", "15.97",
|
||||||
|
"trait_s", "Tool",
|
||||||
"name", "The Zapper");
|
"name", "The Zapper");
|
||||||
add_doc("id", "45", "trait_s", "Chauvinist",
|
add_doc("id", "45",
|
||||||
|
"range_facet_f", "30.0",
|
||||||
|
"trait_s", "Chauvinist",
|
||||||
"title", "25 star General");
|
"title", "25 star General");
|
||||||
add_doc("id", "46", "trait_s", "Obnoxious",
|
add_doc("id", "46",
|
||||||
|
"range_facet_f", "20.0",
|
||||||
|
"trait_s", "Obnoxious",
|
||||||
"subject", "Defeated the pacifists of the Gandhi nebula");
|
"subject", "Defeated the pacifists of the Gandhi nebula");
|
||||||
add_doc("id", "47", "trait_s", "Pig",
|
add_doc("id", "47",
|
||||||
|
"range_facet_f", "28.62",
|
||||||
|
"trait_s", "Pig",
|
||||||
"text", "line up and fly directly at the enemy death cannons, clogging them with wreckage!");
|
"text", "line up and fly directly at the enemy death cannons, clogging them with wreckage!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,23 +292,44 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
add_doc(i, "2014", f, "1976-07-05T22:22:22.222Z");
|
add_doc(i, "2014", f, "1976-07-05T22:22:22.222Z");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrieDateFacets() {
|
||||||
|
helpTestDateFacets("bday", false);
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testDateFacets() {
|
public void testDateFacets() {
|
||||||
final String f = "bday";
|
helpTestDateFacets("bday_pdt", false);
|
||||||
final String pre = "//lst[@name='facet_dates']/lst[@name='"+f+"']";
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrieDateRangeFacets() {
|
||||||
|
helpTestDateFacets("bday", true);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testDateRangeFacets() {
|
||||||
|
helpTestDateFacets("bday_pdt", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void helpTestDateFacets(final String fieldName,
|
||||||
|
final boolean rangeMode) {
|
||||||
|
final String p = rangeMode ? "facet.range" : "facet.date";
|
||||||
|
final String b = rangeMode ? "facet_ranges" : "facet_dates";
|
||||||
|
final String f = fieldName;
|
||||||
|
final String c = (rangeMode ? "/lst[@name='counts']" : "");
|
||||||
|
final String pre = "//lst[@name='"+b+"']/lst[@name='"+f+"']" + c;
|
||||||
|
final String meta = pre + (rangeMode ? "/../" : "");
|
||||||
|
|
||||||
assertQ("check counts for month of facet by day",
|
assertQ("check counts for month of facet by day",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-01T00:00:00.000Z+1MONTH"
|
,p+".end", "1976-07-01T00:00:00.000Z+1MONTH"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
)
|
)
|
||||||
// 31 days + pre+post+inner = 34
|
,"*[count("+pre+"/int)="+(rangeMode ? 31 : 34)+"]"
|
||||||
,"*[count("+pre+"/int)=34]"
|
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0' ]"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0' ]"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
||||||
|
@ -331,9 +363,9 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-30T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-30T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-31T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-31T00:00:00Z'][.='0']"
|
||||||
|
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='after' ][.='1']"
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
,pre+"/int[@name='between'][.='11']"
|
,meta+"/int[@name='between'][.='11']"
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -341,15 +373,14 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-01T00:00:00.000Z+1MONTH"
|
,p+".end", "1976-07-01T00:00:00.000Z+1MONTH"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.mincount", "1"
|
,"facet.mincount", "1"
|
||||||
)
|
)
|
||||||
// 31 days + pre+post+inner = 34
|
,"*[count("+pre+"/int)="+(rangeMode ? 8 : 11)+"]"
|
||||||
,"*[count("+pre+"/int)=11]"
|
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
||||||
// july4th = 2 because exists doc @ 00:00:00.000 on July5
|
// july4th = 2 because exists doc @ 00:00:00.000 on July5
|
||||||
// (date faceting is inclusive)
|
// (date faceting is inclusive)
|
||||||
|
@ -360,68 +391,65 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='1976-07-21T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-21T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-30T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-30T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='after' ][.='1']"
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
,pre+"/int[@name='between'][.='11']"
|
,meta+"/int[@name='between'][.='11']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("check counts for month of facet by day with field mincount = 1",
|
assertQ("check counts for month of facet by day with field mincount = 1",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-01T00:00:00.000Z+1MONTH"
|
,p+".end", "1976-07-01T00:00:00.000Z+1MONTH"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"f." + f + ".facet.mincount", "2"
|
,"f." + f + ".facet.mincount", "2"
|
||||||
)
|
)
|
||||||
// 31 days + pre+post+inner = 34
|
,"*[count("+pre+"/int)="+(rangeMode ? 4 : 7)+"]"
|
||||||
,"*[count("+pre+"/int)=7]"
|
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
||||||
// july4th = 2 because exists doc @ 00:00:00.000 on July5
|
// july4th = 2 because exists doc @ 00:00:00.000 on July5
|
||||||
// (date faceting is inclusive)
|
// (date faceting is inclusive)
|
||||||
,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='after' ][.='1']"
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
,pre+"/int[@name='between'][.='11']"
|
,meta+"/int[@name='between'][.='11']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("check before is not inclusive of upper bound by default",
|
assertQ("check before is not inclusive of upper bound by default",
|
||||||
req("q", "*:*"
|
req("q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-05T00:00:00.000Z"
|
,p+".start", "1976-07-05T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-07T00:00:00.000Z"
|
,p+".end", "1976-07-07T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
)
|
)
|
||||||
// 2 gaps + pre+post+inner = 5
|
,"*[count("+pre+"/int)="+(rangeMode ? 2 : 5)+"]"
|
||||||
,"*[count("+pre+"/int)=5]"
|
|
||||||
,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-05T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]"
|
,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]"
|
||||||
|
|
||||||
,pre+"/int[@name='before' ][.='5']"
|
,meta+"/int[@name='before' ][.='5']"
|
||||||
);
|
);
|
||||||
assertQ("check after is not inclusive of lower bound by default",
|
assertQ("check after is not inclusive of lower bound by default",
|
||||||
req("q", "*:*"
|
req("q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-03T00:00:00.000Z"
|
,p+".start", "1976-07-03T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-05T00:00:00.000Z"
|
,p+".end", "1976-07-05T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
)
|
)
|
||||||
// 2 gaps + pre+post+inner = 5
|
,"*[count("+pre+"/int)="+(rangeMode ? 2 : 5)+"]"
|
||||||
,"*[count("+pre+"/int)=5]"
|
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-04T00:00:00Z'][.='2' ]"
|
||||||
|
|
||||||
,pre+"/int[@name='after' ][.='8']"
|
,meta+"/int[@name='after' ][.='8']"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -429,68 +457,88 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-13T00:00:00.000Z"
|
,p+".end", "1976-07-13T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+5DAYS"
|
,p+".gap", "+5DAYS"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.hardend","false"
|
,p+".hardend","false"
|
||||||
)
|
)
|
||||||
// 3 gaps + pre+post+inner = 6
|
,"*[count("+pre+"/int)="+(rangeMode ? 3 : 6)+"]"
|
||||||
,"*[count("+pre+"/int)=6]"
|
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='5' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='5' ]"
|
||||||
,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]"
|
,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]"
|
||||||
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='4' ]"
|
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='4' ]"
|
||||||
|
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='after' ][.='3']"
|
,meta+"/int[@name='after' ][.='3']"
|
||||||
,pre+"/int[@name='between'][.='9']"
|
,meta+"/int[@name='between'][.='9']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("check hardend=true",
|
assertQ("check hardend=true",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-13T00:00:00.000Z"
|
,p+".end", "1976-07-13T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+5DAYS"
|
,p+".gap", "+5DAYS"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.hardend","true"
|
,p+".hardend","true"
|
||||||
)
|
)
|
||||||
// 3 gaps + pre+post+inner = 6
|
,"*[count("+pre+"/int)="+(rangeMode ? 3 : 6)+"]"
|
||||||
,"*[count("+pre+"/int)=6]"
|
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='5' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='5' ]"
|
||||||
,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]"
|
,pre+"/int[@name='1976-07-06T00:00:00Z'][.='0' ]"
|
||||||
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='1' ]"
|
||||||
|
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='after' ][.='6']"
|
,meta+"/int[@name='after' ][.='6']"
|
||||||
,pre+"/int[@name='between'][.='6']"
|
,meta+"/int[@name='between'][.='6']"
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** similar to testDateFacets, but a differnet field with test data
|
@Test
|
||||||
exactly on on boundary marks */
|
public void testTrieDateFacetsWithIncludeOption() {
|
||||||
|
helpTestDateFacetsWithIncludeOption("a_tdt", false);
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testDateFacetsWithIncludeOption() {
|
public void testDateFacetsWithIncludeOption() {
|
||||||
final String f = "a_tdt";
|
helpTestDateFacetsWithIncludeOption("a_pdt", false);
|
||||||
final String pre = "//lst[@name='facet_dates']/lst[@name='"+f+"']";
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrieDateRangeFacetsWithIncludeOption() {
|
||||||
|
helpTestDateFacetsWithIncludeOption("a_tdt", true);
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testDateRangeFacetsWithIncludeOption() {
|
||||||
|
helpTestDateFacetsWithIncludeOption("a_pdt", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** similar to helpTestDateFacets, but for differnet fields with test data
|
||||||
|
exactly on on boundary marks */
|
||||||
|
private void helpTestDateFacetsWithIncludeOption(final String fieldName,
|
||||||
|
final boolean rangeMode) {
|
||||||
|
final String p = rangeMode ? "facet.range" : "facet.date";
|
||||||
|
final String b = rangeMode ? "facet_ranges" : "facet_dates";
|
||||||
|
final String f = fieldName;
|
||||||
|
final String c = (rangeMode ? "/lst[@name='counts']" : "");
|
||||||
|
final String pre = "//lst[@name='"+b+"']/lst[@name='"+f+"']" + c;
|
||||||
|
final String meta = pre + (rangeMode ? "/../" : "");
|
||||||
|
|
||||||
assertQ("checking counts for lower",
|
assertQ("checking counts for lower",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-16T00:00:00.000Z"
|
,p+".end", "1976-07-16T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "lower"
|
,p+".include", "lower"
|
||||||
)
|
)
|
||||||
// 15 days + pre+post+inner = 18
|
// 15 days + pre+post+inner = 18
|
||||||
,"*[count("+pre+"/int)=18]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
||||||
|
@ -506,24 +554,25 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='1']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='1']"
|
,meta+"/int[@name='before' ][.='1']"
|
||||||
,pre+"/int[@name='between'][.='8']"
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
|
,meta+"/int[@name='between'][.='8']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for upper",
|
assertQ("checking counts for upper",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-16T00:00:00.000Z"
|
,p+".end", "1976-07-16T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "upper"
|
,p+".include", "upper"
|
||||||
)
|
)
|
||||||
// 15 days + pre+post+inner = 18
|
// 15 days + pre+post+inner = 18
|
||||||
,"*[count("+pre+"/int)=18]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
||||||
|
@ -539,25 +588,26 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='1']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='between'][.='7']"
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
|
,meta+"/int[@name='between'][.='7']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for lower & upper",
|
assertQ("checking counts for lower & upper",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-16T00:00:00.000Z"
|
,p+".end", "1976-07-16T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "lower"
|
,p+".include", "lower"
|
||||||
,"facet.date.include", "upper"
|
,p+".include", "upper"
|
||||||
)
|
)
|
||||||
// 15 days + pre+post+inner = 18
|
// 15 days + pre+post+inner = 18
|
||||||
,"*[count("+pre+"/int)=18]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
||||||
|
@ -573,25 +623,26 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2' ]"
|
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='2' ]"
|
||||||
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='1']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='1']"
|
,meta+"/int[@name='before' ][.='1']"
|
||||||
,pre+"/int[@name='between'][.='8']"
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
|
,meta+"/int[@name='between'][.='8']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for upper & edge",
|
assertQ("checking counts for upper & edge",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-16T00:00:00.000Z"
|
,p+".end", "1976-07-16T00:00:00.000Z"
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "upper"
|
,p+".include", "upper"
|
||||||
,"facet.date.include", "edge"
|
,p+".include", "edge"
|
||||||
)
|
)
|
||||||
// 15 days + pre+post+inner = 18
|
// 15 days + pre+post+inner = 18
|
||||||
,"*[count("+pre+"/int)=18]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 15 : 18)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
||||||
|
@ -607,25 +658,26 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-13T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-14T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-15T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='1']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='1']"
|
,meta+"/int[@name='before' ][.='1']"
|
||||||
,pre+"/int[@name='between'][.='8']"
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
|
,meta+"/int[@name='between'][.='8']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for upper & outer",
|
assertQ("checking counts for upper & outer",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-13T00:00:00.000Z" // smaller now
|
,p+".end", "1976-07-13T00:00:00.000Z" // smaller now
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "upper"
|
,p+".include", "upper"
|
||||||
,"facet.date.include", "outer"
|
,p+".include", "outer"
|
||||||
)
|
)
|
||||||
// 12 days + pre+post+inner = 15
|
// 12 days + pre+post+inner = 15
|
||||||
,"*[count("+pre+"/int)=15]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
||||||
|
@ -638,25 +690,26 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='4']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='between'][.='5']"
|
,meta+"/int[@name='after' ][.='4']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for lower & edge",
|
assertQ("checking counts for lower & edge",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-13T00:00:00.000Z" // smaller now
|
,p+".end", "1976-07-13T00:00:00.000Z" // smaller now
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "lower"
|
,p+".include", "lower"
|
||||||
,"facet.date.include", "edge"
|
,p+".include", "edge"
|
||||||
)
|
)
|
||||||
// 12 days + pre+post+inner = 15
|
// 12 days + pre+post+inner = 15
|
||||||
,"*[count("+pre+"/int)=15]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
||||||
|
@ -669,25 +722,26 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='1']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='3']"
|
,meta+"/int[@name='before' ][.='1']"
|
||||||
,pre+"/int[@name='between'][.='6']"
|
,meta+"/int[@name='after' ][.='3']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for lower & outer",
|
assertQ("checking counts for lower & outer",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-13T00:00:00.000Z" // smaller now
|
,p+".end", "1976-07-13T00:00:00.000Z" // smaller now
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "lower"
|
,p+".include", "lower"
|
||||||
,"facet.date.include", "outer"
|
,p+".include", "outer"
|
||||||
)
|
)
|
||||||
// 12 days + pre+post+inner = 15
|
// 12 days + pre+post+inner = 15
|
||||||
,"*[count("+pre+"/int)=15]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
||||||
|
@ -700,26 +754,27 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='4']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='between'][.='5']"
|
,meta+"/int[@name='after' ][.='4']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for lower & edge & outer",
|
assertQ("checking counts for lower & edge & outer",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-13T00:00:00.000Z" // smaller now
|
,p+".end", "1976-07-13T00:00:00.000Z" // smaller now
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "lower"
|
,p+".include", "lower"
|
||||||
,"facet.date.include", "edge"
|
,p+".include", "edge"
|
||||||
,"facet.date.include", "outer"
|
,p+".include", "outer"
|
||||||
)
|
)
|
||||||
// 12 days + pre+post+inner = 15
|
// 12 days + pre+post+inner = 15
|
||||||
,"*[count("+pre+"/int)=15]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='0']"
|
||||||
|
@ -732,24 +787,25 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='4']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='between'][.='6']"
|
,meta+"/int[@name='after' ][.='4']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
);
|
);
|
||||||
|
|
||||||
assertQ("checking counts for all",
|
assertQ("checking counts for all",
|
||||||
req( "q", "*:*"
|
req( "q", "*:*"
|
||||||
,"rows", "0"
|
,"rows", "0"
|
||||||
,"facet", "true"
|
,"facet", "true"
|
||||||
,"facet.date", f
|
,p, f
|
||||||
,"facet.date.start", "1976-07-01T00:00:00.000Z"
|
,p+".start", "1976-07-01T00:00:00.000Z"
|
||||||
,"facet.date.end", "1976-07-13T00:00:00.000Z" // smaller now
|
,p+".end", "1976-07-13T00:00:00.000Z" // smaller now
|
||||||
,"facet.date.gap", "+1DAY"
|
,p+".gap", "+1DAY"
|
||||||
,"facet.date.other", "all"
|
,p+".other", "all"
|
||||||
,"facet.date.include", "all"
|
,p+".include", "all"
|
||||||
)
|
)
|
||||||
// 12 days + pre+post+inner = 15
|
// 12 days + pre+post+inner = 15
|
||||||
,"*[count("+pre+"/int)=15]"
|
,"*[count("+pre+"/int)="+(rangeMode ? 12 : 15)+"]"
|
||||||
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-01T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-02T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-03T00:00:00Z'][.='1' ]"
|
||||||
|
@ -762,12 +818,302 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
||||||
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-10T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
,pre+"/int[@name='1976-07-11T00:00:00Z'][.='0']"
|
||||||
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
,pre+"/int[@name='1976-07-12T00:00:00Z'][.='1' ]"
|
||||||
,pre+"/int[@name='before' ][.='2']"
|
//
|
||||||
,pre+"/int[@name='after' ][.='4']"
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
,pre+"/int[@name='between'][.='6']"
|
,meta+"/int[@name='after' ][.='4']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsTrieFloat() {
|
||||||
|
helpTestFractionalNumberRangeFacets("range_facet_f");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsTrieDouble() {
|
||||||
|
helpTestFractionalNumberRangeFacets("range_facet_d");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsSortableFloat() {
|
||||||
|
helpTestFractionalNumberRangeFacets("range_facet_sf");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsSortableDouble() {
|
||||||
|
helpTestFractionalNumberRangeFacets("range_facet_sd");
|
||||||
|
}
|
||||||
|
private void helpTestFractionalNumberRangeFacets(final String fieldName) {
|
||||||
|
|
||||||
|
final String f = fieldName;
|
||||||
|
final String pre = "//lst[@name='facet_ranges']/lst[@name='"+f+"']/lst[@name='counts']";
|
||||||
|
final String meta = pre + "/../";
|
||||||
|
|
||||||
|
assertQ(f+": checking counts for lower",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "10"
|
||||||
|
,"facet.range.end", "50"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "lower"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=4]"
|
||||||
|
,pre+"/int[@name='10.0'][.='1' ]"
|
||||||
|
,pre+"/int[@name='20.0'][.='3' ]"
|
||||||
|
,pre+"/int[@name='30.0'][.='2' ]"
|
||||||
|
,pre+"/int[@name='40.0'][.='0' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='0']"
|
||||||
|
,meta+"/int[@name='after' ][.='0']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ":checking counts for upper",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "10"
|
||||||
|
,"facet.range.end", "50"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "upper"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=4]"
|
||||||
|
,pre+"/int[@name='10.0'][.='2' ]"
|
||||||
|
,pre+"/int[@name='20.0'][.='3' ]"
|
||||||
|
,pre+"/int[@name='30.0'][.='1' ]"
|
||||||
|
,pre+"/int[@name='40.0'][.='0' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='0']"
|
||||||
|
,meta+"/int[@name='after' ][.='0']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ":checking counts for lower & upper",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "10"
|
||||||
|
,"facet.range.end", "50"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "upper"
|
||||||
|
,"facet.range.include", "lower"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=4]"
|
||||||
|
,pre+"/int[@name='10.0'][.='2' ]"
|
||||||
|
,pre+"/int[@name='20.0'][.='4' ]"
|
||||||
|
,pre+"/int[@name='30.0'][.='2' ]"
|
||||||
|
,pre+"/int[@name='40.0'][.='0' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='0']"
|
||||||
|
,meta+"/int[@name='after' ][.='0']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ": checking counts for upper & edge",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "20"
|
||||||
|
,"facet.range.end", "50"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "upper"
|
||||||
|
,"facet.range.include", "edge"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=3]"
|
||||||
|
,pre+"/int[@name='20.0'][.='4' ]"
|
||||||
|
,pre+"/int[@name='30.0'][.='1' ]"
|
||||||
|
,pre+"/int[@name='40.0'][.='0' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='1']"
|
||||||
|
,meta+"/int[@name='after' ][.='0']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ": checking counts for upper & outer",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "10"
|
||||||
|
,"facet.range.end", "30"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "upper"
|
||||||
|
,"facet.range.include", "outer"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=2]"
|
||||||
|
,pre+"/int[@name='10.0'][.='2' ]"
|
||||||
|
,pre+"/int[@name='20.0'][.='3' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='0']"
|
||||||
|
,meta+"/int[@name='after' ][.='2']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ": checking counts for lower & edge",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "10"
|
||||||
|
,"facet.range.end", "30"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "lower"
|
||||||
|
,"facet.range.include", "edge"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=2]"
|
||||||
|
,pre+"/int[@name='10.0'][.='1' ]"
|
||||||
|
,pre+"/int[@name='20.0'][.='4' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='0']"
|
||||||
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ": checking counts for lower & outer",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "20"
|
||||||
|
,"facet.range.end", "40"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "lower"
|
||||||
|
,"facet.range.include", "outer"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=2]"
|
||||||
|
,pre+"/int[@name='20.0'][.='3' ]"
|
||||||
|
,pre+"/int[@name='30.0'][.='2' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
|
,meta+"/int[@name='after' ][.='0']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ": checking counts for lower & edge & outer",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "20"
|
||||||
|
,"facet.range.end", "35.3"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.hardend", "true"
|
||||||
|
,"facet.range.include", "lower"
|
||||||
|
,"facet.range.include", "edge"
|
||||||
|
,"facet.range.include", "outer"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=2]"
|
||||||
|
,pre+"/int[@name='20.0'][.='3' ]"
|
||||||
|
,pre+"/int[@name='30.0'][.='2' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ": checking counts for include all",
|
||||||
|
req( "q", "*:*"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "20"
|
||||||
|
,"facet.range.end", "35.3"
|
||||||
|
,"facet.range.gap", "10"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.hardend", "true"
|
||||||
|
,"facet.range.include", "all"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=2]"
|
||||||
|
,pre+"/int[@name='20.0'][.='4' ]"
|
||||||
|
,pre+"/int[@name='30.0'][.='2' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='2']"
|
||||||
|
,meta+"/int[@name='after' ][.='1']"
|
||||||
|
,meta+"/int[@name='between'][.='5']"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsTrieInt() {
|
||||||
|
helpTestWholeNumberRangeFacets("id");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsTrieLong() {
|
||||||
|
helpTestWholeNumberRangeFacets("range_facet_l");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsSortableInt() {
|
||||||
|
helpTestWholeNumberRangeFacets("range_facet_si");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
public void testNumericRangeFacetsSortableLong() {
|
||||||
|
helpTestWholeNumberRangeFacets("range_facet_sl");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void helpTestWholeNumberRangeFacets(final String fieldName) {
|
||||||
|
|
||||||
|
// the float test covers a lot of the weird edge cases
|
||||||
|
// here we just need some basic sanity checking of the parsing
|
||||||
|
|
||||||
|
final String f = fieldName;
|
||||||
|
final String pre = "//lst[@name='facet_ranges']/lst[@name='"+f+"']/lst[@name='counts']";
|
||||||
|
final String meta = pre + "/../";
|
||||||
|
|
||||||
|
assertQ(f+": checking counts for lower",
|
||||||
|
req( "q", "id:[30 TO 60]"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "35"
|
||||||
|
,"facet.range.end", "50"
|
||||||
|
,"facet.range.gap", "5"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "lower"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=3]"
|
||||||
|
,pre+"/int[@name='35'][.='0' ]"
|
||||||
|
,pre+"/int[@name='40'][.='3' ]"
|
||||||
|
,pre+"/int[@name='45'][.='3' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='0']"
|
||||||
|
,meta+"/int[@name='after' ][.='0']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
|
);
|
||||||
|
|
||||||
|
assertQ(f + ":checking counts for upper",
|
||||||
|
req( "q", "id:[30 TO 60]"
|
||||||
|
,"rows", "0"
|
||||||
|
,"facet", "true"
|
||||||
|
,"facet.range", f
|
||||||
|
,"facet.range.start", "35"
|
||||||
|
,"facet.range.end", "50"
|
||||||
|
,"facet.range.gap", "5"
|
||||||
|
,"facet.range.other", "all"
|
||||||
|
,"facet.range.include", "upper"
|
||||||
|
)
|
||||||
|
,"*[count("+pre+"/int)=3]"
|
||||||
|
,pre+"/int[@name='35'][.='0' ]"
|
||||||
|
,pre+"/int[@name='40'][.='4' ]"
|
||||||
|
,pre+"/int[@name='45'][.='2' ]"
|
||||||
|
//
|
||||||
|
,meta+"/int[@name='before' ][.='0']"
|
||||||
|
,meta+"/int[@name='after' ][.='0']"
|
||||||
|
,meta+"/int[@name='between'][.='6']"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void indexFacetSingleValued() {
|
static void indexFacetSingleValued() {
|
||||||
indexFacets("40","t_s1");
|
indexFacets("40","t_s1");
|
||||||
}
|
}
|
||||||
|
|
|
@ -565,6 +565,17 @@
|
||||||
|
|
||||||
<copyField source="*_t" dest="text"/>
|
<copyField source="*_t" dest="text"/>
|
||||||
|
|
||||||
|
<copyField source="id" dest="range_facet_si"/>
|
||||||
|
<copyField source="id" dest="range_facet_l"/>
|
||||||
|
<copyField source="id" dest="range_facet_sl"/>
|
||||||
|
<copyField source="range_facet_f" dest="range_facet_sf"/>
|
||||||
|
<copyField source="range_facet_f" dest="range_facet_d"/>
|
||||||
|
<copyField source="range_facet_f" dest="range_facet_sd"/>
|
||||||
|
|
||||||
|
<copyField source="bday" dest="bday_pdt"/>
|
||||||
|
<copyField source="a_tdt" dest="a_pdt"/>
|
||||||
|
|
||||||
|
|
||||||
<!-- dynamic destination -->
|
<!-- dynamic destination -->
|
||||||
<copyField source="*_dynamic" dest="dynamic_*"/>
|
<copyField source="*_dynamic" dest="dynamic_*"/>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue