mirror of https://github.com/apache/lucene.git
SOLR-6686: facet.threads can return wrong results when using facet.prefix multiple times on same field
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1687791 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
42fdbbeb95
commit
878881a77a
|
@ -186,6 +186,9 @@ Bug Fixes
|
|||
* SOLR-7664: Throw correct exception (RemoteSolrException) on receiving a HTTP 413.
|
||||
(Ramkumar Aiyengar, Eirik Lygre)
|
||||
|
||||
* SOLR-6686: facet.threads can return wrong results when using facet.prefix multiple
|
||||
times on same field. (Michael Ryan, Tim Underwood via shalin)
|
||||
|
||||
Optimizations
|
||||
----------------------
|
||||
|
||||
|
|
|
@ -76,13 +76,14 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
|
||||
SimpleOrderedMap<List<NamedList<Object>>> pivotResponse = new SimpleOrderedMap<>();
|
||||
for (String pivotList : pivots) {
|
||||
final ParsedParams parsed;
|
||||
|
||||
try {
|
||||
// NOTE: this sets localParams (SimpleFacets is stateful)
|
||||
this.parseParams(FacetParams.FACET_PIVOT, pivotList);
|
||||
parsed = this.parseParams(FacetParams.FACET_PIVOT, pivotList);
|
||||
} catch (SyntaxError e) {
|
||||
throw new SolrException(ErrorCode.BAD_REQUEST, e);
|
||||
}
|
||||
List<String> pivotFields = StrUtils.splitSmart(facetValue, ",", true);
|
||||
List<String> pivotFields = StrUtils.splitSmart(parsed.facetValue, ",", true);
|
||||
if( pivotFields.size() < 1 ) {
|
||||
throw new SolrException( ErrorCode.BAD_REQUEST,
|
||||
"Pivot Facet needs at least one field name: " + pivotList);
|
||||
|
@ -101,11 +102,11 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
String refineKey = null; // no local => no refinement
|
||||
List<StatsField> statsFields = Collections.emptyList(); // no local => no stats
|
||||
|
||||
if (null != localParams) {
|
||||
if (null != parsed.localParams) {
|
||||
// we might be refining..
|
||||
refineKey = localParams.get(PivotFacet.REFINE_PARAM);
|
||||
refineKey = parsed.localParams.get(PivotFacet.REFINE_PARAM);
|
||||
|
||||
String statsLocalParam = localParams.get(StatsParams.STATS);
|
||||
String statsLocalParam = parsed.localParams.get(StatsParams.STATS);
|
||||
if (null != refineKey
|
||||
&& null != statsLocalParam
|
||||
&& null == statsInfo) {
|
||||
|
@ -123,10 +124,10 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
= params.getParams(PivotFacet.REFINE_PARAM + refineKey);
|
||||
|
||||
for(String refinements : refinementValuesByField){
|
||||
pivotResponse.addAll(processSingle(pivotFields, refinements, statsFields));
|
||||
pivotResponse.addAll(processSingle(pivotFields, refinements, statsFields, parsed));
|
||||
}
|
||||
} else{
|
||||
pivotResponse.addAll(processSingle(pivotFields, null, statsFields));
|
||||
pivotResponse.addAll(processSingle(pivotFields, null, statsFields, parsed));
|
||||
}
|
||||
}
|
||||
return pivotResponse;
|
||||
|
@ -141,7 +142,8 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
private SimpleOrderedMap<List<NamedList<Object>>> processSingle
|
||||
(List<String> pivotFields,
|
||||
String refinements,
|
||||
List<StatsField> statsFields) throws IOException {
|
||||
List<StatsField> statsFields,
|
||||
final ParsedParams parsed) throws IOException {
|
||||
|
||||
SolrIndexSearcher searcher = rb.req.getSearcher();
|
||||
SimpleOrderedMap<List<NamedList<Object>>> pivotResponse = new SimpleOrderedMap<>();
|
||||
|
@ -170,18 +172,18 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
|
||||
facetCounts = new NamedList<>();
|
||||
facetCounts.add(firstFieldsValues,
|
||||
getSubsetSize(this.docs, sfield, firstFieldsValues));
|
||||
getSubsetSize(parsed.docs, sfield, firstFieldsValues));
|
||||
} else {
|
||||
// no refinements needed
|
||||
facetCounts = this.getTermCountsForPivots(field, this.docs);
|
||||
facetCounts = this.getTermCountsForPivots(field, parsed);
|
||||
}
|
||||
|
||||
if(pivotFields.size() > 1) {
|
||||
String subField = pivotFields.get(1);
|
||||
pivotResponse.add(key,
|
||||
doPivots(facetCounts, field, subField, fnames, vnames, this.docs, statsFields));
|
||||
pivotResponse.add(parsed.key,
|
||||
doPivots(facetCounts, field, subField, fnames, vnames, parsed, statsFields));
|
||||
} else {
|
||||
pivotResponse.add(key, doPivots(facetCounts, field, null, fnames, vnames, this.docs, statsFields));
|
||||
pivotResponse.add(parsed.key, doPivots(facetCounts, field, null, fnames, vnames, parsed, statsFields));
|
||||
}
|
||||
return pivotResponse;
|
||||
}
|
||||
|
@ -223,7 +225,7 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
protected List<NamedList<Object>> doPivots(NamedList<Integer> superFacets,
|
||||
String field, String subField,
|
||||
Deque<String> fnames, Deque<String> vnames,
|
||||
DocSet docs, List<StatsField> statsFields)
|
||||
ParsedParams parsed, List<StatsField> statsFields)
|
||||
throws IOException {
|
||||
|
||||
boolean isShard = rb.req.getParams().getBool(ShardParams.IS_SHARD, false);
|
||||
|
@ -255,7 +257,7 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
}
|
||||
pivot.add( "count", pivotCount );
|
||||
|
||||
DocSet subset = getSubset(docs, sfield, fieldValue);
|
||||
final DocSet subset = getSubset(parsed.docs, sfield, fieldValue);
|
||||
|
||||
if( subField != null ) {
|
||||
NamedList<Integer> facetCounts;
|
||||
|
@ -266,11 +268,11 @@ public class PivotFacetProcessor extends SimpleFacets
|
|||
searcher.getSchema().getField(subField),
|
||||
val));
|
||||
} else {
|
||||
facetCounts = this.getTermCountsForPivots(subField, subset);
|
||||
facetCounts = this.getTermCountsForPivots(subField, parsed.withDocs(subset));
|
||||
}
|
||||
|
||||
if (facetCounts.size() >= 1) {
|
||||
pivot.add( "pivot", doPivots( facetCounts, subField, nextField, fnames, vnames, subset, statsFields ) );
|
||||
pivot.add( "pivot", doPivots( facetCounts, subField, nextField, fnames, vnames, parsed.withDocs(subset), statsFields ) );
|
||||
}
|
||||
}
|
||||
if ((isShard || 0 < pivotCount) && ! statsFields.isEmpty()) {
|
||||
|
|
|
@ -115,7 +115,7 @@ public class SimpleFacets {
|
|||
/** The main set of documents all facet counts should be relative to */
|
||||
protected DocSet docsOrig;
|
||||
/** Configuration params behavior should be driven by */
|
||||
protected final SolrParams orig;
|
||||
protected final SolrParams global;
|
||||
/** Searcher to use for all calculations */
|
||||
protected final SolrIndexSearcher searcher;
|
||||
protected final SolrQueryRequest req;
|
||||
|
@ -124,14 +124,36 @@ public class SimpleFacets {
|
|||
protected SimpleOrderedMap<Object> facetResponse;
|
||||
|
||||
// per-facet values
|
||||
protected SolrParams localParams; // localParams on this particular facet command
|
||||
protected SolrParams params; // local+original
|
||||
protected SolrParams required; // required version of params
|
||||
protected String facetValue; // the field to or query to facet on (minus local params)
|
||||
protected DocSet docs; // the base docset for this particular facet
|
||||
protected String key; // what name should the results be stored under
|
||||
protected int threads;
|
||||
|
||||
protected final static class ParsedParams {
|
||||
final public SolrParams localParams; // localParams on this particular facet command
|
||||
final public SolrParams params; // local+original
|
||||
final public SolrParams required; // required version of params
|
||||
final public String facetValue; // the field to or query to facet on (minus local params)
|
||||
final public DocSet docs; // the base docset for this particular facet
|
||||
final public String key; // what name should the results be stored under
|
||||
final public int threads;
|
||||
|
||||
public ParsedParams(final SolrParams localParams, // localParams on this particular facet command
|
||||
final SolrParams params, // local+original
|
||||
final SolrParams required, // required version of params
|
||||
final String facetValue, // the field to or query to facet on (minus local params)
|
||||
final DocSet docs, // the base docset for this particular facet
|
||||
final String key, // what name should the results be stored under
|
||||
final int threads) {
|
||||
this.localParams = localParams;
|
||||
this.params = params;
|
||||
this.required = required;
|
||||
this.facetValue = facetValue;
|
||||
this.docs = docs;
|
||||
this.key = key;
|
||||
this.threads = threads;
|
||||
}
|
||||
|
||||
public ParsedParams withDocs(final DocSet docs) {
|
||||
return new ParsedParams(localParams, params, required, facetValue, docs, key, threads);
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleFacets(SolrQueryRequest req,
|
||||
DocSet docs,
|
||||
SolrParams params) {
|
||||
|
@ -144,9 +166,8 @@ public class SimpleFacets {
|
|||
ResponseBuilder rb) {
|
||||
this.req = req;
|
||||
this.searcher = req.getSearcher();
|
||||
this.docs = this.docsOrig = docs;
|
||||
this.params = orig = params;
|
||||
this.required = new RequiredSolrParams(params);
|
||||
this.docsOrig = docs;
|
||||
this.global = params;
|
||||
this.rb = rb;
|
||||
}
|
||||
|
||||
|
@ -170,20 +191,21 @@ public class SimpleFacets {
|
|||
}
|
||||
|
||||
|
||||
protected void parseParams(String type, String param) throws SyntaxError, IOException {
|
||||
localParams = QueryParsing.getLocalParams(param, req.getParams());
|
||||
docs = docsOrig;
|
||||
facetValue = param;
|
||||
key = param;
|
||||
threads = -1;
|
||||
protected ParsedParams parseParams(String type, String param) throws SyntaxError, IOException {
|
||||
SolrParams localParams = QueryParsing.getLocalParams(param, req.getParams());
|
||||
DocSet docs = docsOrig;
|
||||
String facetValue = param;
|
||||
String key = param;
|
||||
int threads = -1;
|
||||
|
||||
if (localParams == null) {
|
||||
params = orig;
|
||||
required = new RequiredSolrParams(params);
|
||||
return;
|
||||
SolrParams params = global;
|
||||
SolrParams required = new RequiredSolrParams(params);
|
||||
return new ParsedParams(localParams, params, required, facetValue, docs, key, threads);
|
||||
}
|
||||
params = SolrParams.wrapDefaults(localParams, orig);
|
||||
required = new RequiredSolrParams(params);
|
||||
|
||||
SolrParams params = SolrParams.wrapDefaults(localParams, global);
|
||||
SolrParams required = new RequiredSolrParams(params);
|
||||
|
||||
// remove local params unless it's a query
|
||||
if (type != FacetParams.FACET_QUERY) { // TODO Cut over to an Enum here
|
||||
|
@ -203,7 +225,7 @@ public class SimpleFacets {
|
|||
|
||||
// figure out if we need a new base DocSet
|
||||
String excludeStr = localParams.get(CommonParams.EXCLUDE);
|
||||
if (excludeStr == null) return;
|
||||
if (excludeStr == null) return new ParsedParams(localParams, params, required, facetValue, docs, key, threads);
|
||||
|
||||
Map<?,?> tagMap = (Map<?,?>)req.getContext().get("tags");
|
||||
if (tagMap != null && rb != null) {
|
||||
|
@ -220,7 +242,7 @@ public class SimpleFacets {
|
|||
excludeSet.put(qp.getQuery(), Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
if (excludeSet.size() == 0) return;
|
||||
if (excludeSet.size() == 0) return new ParsedParams(localParams, params, required, facetValue, docs, key, threads);
|
||||
|
||||
List<Query> qlist = new ArrayList<>();
|
||||
|
||||
|
@ -248,17 +270,18 @@ public class SimpleFacets {
|
|||
} else if (rb.getGroupingSpec().getFunctions().length > 0) {
|
||||
grouping.addFunctionCommand(rb.getGroupingSpec().getFunctions()[0], req);
|
||||
} else {
|
||||
this.docs = base;
|
||||
return;
|
||||
docs = base;
|
||||
return new ParsedParams(localParams, params, required, facetValue, docs, key, threads);
|
||||
}
|
||||
AbstractAllGroupHeadsCollector allGroupHeadsCollector = grouping.getCommands().get(0).createAllGroupCollector();
|
||||
searcher.search(base.getTopFilter(), allGroupHeadsCollector);
|
||||
this.docs = new BitDocSet(allGroupHeadsCollector.retrieveGroupHeads(searcher.maxDoc()));
|
||||
docs = new BitDocSet(allGroupHeadsCollector.retrieveGroupHeads(searcher.maxDoc()));
|
||||
} else {
|
||||
this.docs = base;
|
||||
docs = base;
|
||||
}
|
||||
}
|
||||
|
||||
return new ParsedParams(localParams, params, required, facetValue, docs, key, threads);
|
||||
}
|
||||
|
||||
|
||||
|
@ -277,7 +300,7 @@ public class SimpleFacets {
|
|||
public NamedList<Object> getFacetCounts() {
|
||||
|
||||
// if someone called this method, benefit of the doubt: assume true
|
||||
if (!params.getBool(FacetParams.FACET,true))
|
||||
if (!global.getBool(FacetParams.FACET,true))
|
||||
return null;
|
||||
|
||||
facetResponse = new SimpleOrderedMap<>();
|
||||
|
@ -313,21 +336,21 @@ public class SimpleFacets {
|
|||
*/
|
||||
// SolrQueryParser qp = searcher.getSchema().getSolrQueryParser(null);
|
||||
|
||||
String[] facetQs = params.getParams(FacetParams.FACET_QUERY);
|
||||
String[] facetQs = global.getParams(FacetParams.FACET_QUERY);
|
||||
|
||||
if (null != facetQs && 0 != facetQs.length) {
|
||||
for (String q : facetQs) {
|
||||
parseParams(FacetParams.FACET_QUERY, q);
|
||||
final ParsedParams parsed = parseParams(FacetParams.FACET_QUERY, q);
|
||||
|
||||
// TODO: slight optimization would prevent double-parsing of any localParams
|
||||
Query qobj = QParser.getParser(q, null, req).getQuery();
|
||||
|
||||
if (qobj == null) {
|
||||
res.add(key, 0);
|
||||
} else if (params.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
res.add(key, getGroupedFacetQueryCount(qobj));
|
||||
res.add(parsed.key, 0);
|
||||
} else if (parsed.params.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
res.add(parsed.key, getGroupedFacetQueryCount(qobj, parsed));
|
||||
} else {
|
||||
res.add(key, searcher.numDocs(qobj, docs));
|
||||
res.add(parsed.key, searcher.numDocs(qobj, parsed.docs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,8 +363,8 @@ public class SimpleFacets {
|
|||
*
|
||||
* @see FacetParams#FACET_QUERY
|
||||
*/
|
||||
public int getGroupedFacetQueryCount(Query facetQuery) throws IOException {
|
||||
String groupField = params.get(GroupParams.GROUP_FIELD);
|
||||
public int getGroupedFacetQueryCount(Query facetQuery, ParsedParams parsed) throws IOException {
|
||||
String groupField = parsed.params.get(GroupParams.GROUP_FIELD);
|
||||
if (groupField == null) {
|
||||
throw new SolrException (
|
||||
SolrException.ErrorCode.BAD_REQUEST,
|
||||
|
@ -350,7 +373,7 @@ public class SimpleFacets {
|
|||
}
|
||||
|
||||
TermAllGroupsCollector collector = new TermAllGroupsCollector(groupField);
|
||||
Filter mainQueryFilter = docs.getTopFilter(); // This returns a filter that only matches documents matching with q param and fq params
|
||||
Filter mainQueryFilter = parsed.docs.getTopFilter(); // This returns a filter that only matches documents matching with q param and fq params
|
||||
Query filteredFacetQuery = new BooleanQuery.Builder()
|
||||
.add(facetQuery, Occur.MUST)
|
||||
.add(mainQueryFilter, Occur.FILTER)
|
||||
|
@ -367,9 +390,9 @@ public class SimpleFacets {
|
|||
* Term counts for use in pivot faceting that resepcts the appropriate mincount
|
||||
* @see FacetParams#FACET_PIVOT_MINCOUNT
|
||||
*/
|
||||
public NamedList<Integer> getTermCountsForPivots(String field, DocSet docs) throws IOException {
|
||||
Integer mincount = params.getFieldInt(field, FacetParams.FACET_PIVOT_MINCOUNT, 1);
|
||||
return getTermCounts(field, mincount, docs);
|
||||
public NamedList<Integer> getTermCountsForPivots(String field, ParsedParams parsed) throws IOException {
|
||||
Integer mincount = parsed.params.getFieldInt(field, FacetParams.FACET_PIVOT_MINCOUNT, 1);
|
||||
return getTermCounts(field, mincount, parsed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -377,18 +400,9 @@ public class SimpleFacets {
|
|||
*
|
||||
* @see FacetParams#FACET_MINCOUNT
|
||||
*/
|
||||
public NamedList<Integer> getTermCounts(String field) throws IOException {
|
||||
return getTermCounts(field, this.docs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Term counts for use in field faceting that resepects the appropriate mincount
|
||||
*
|
||||
* @see FacetParams#FACET_MINCOUNT
|
||||
*/
|
||||
public NamedList<Integer> getTermCounts(String field, DocSet base) throws IOException {
|
||||
Integer mincount = params.getFieldInt(field, FacetParams.FACET_MINCOUNT);
|
||||
return getTermCounts(field, mincount, base);
|
||||
public NamedList<Integer> getTermCounts(String field, ParsedParams parsed) throws IOException {
|
||||
Integer mincount = parsed.params.getFieldInt(field, FacetParams.FACET_MINCOUNT);
|
||||
return getTermCounts(field, mincount, parsed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -398,7 +412,10 @@ public class SimpleFacets {
|
|||
*
|
||||
* @see FacetParams#FACET_ZEROS
|
||||
*/
|
||||
private NamedList<Integer> getTermCounts(String field, Integer mincount, DocSet base) throws IOException {
|
||||
private NamedList<Integer> getTermCounts(String field, Integer mincount, ParsedParams parsed) throws IOException {
|
||||
final SolrParams params = parsed.params;
|
||||
final DocSet docs = parsed.docs;
|
||||
final int threads = parsed.threads;
|
||||
int offset = params.getFieldInt(field, FacetParams.FACET_OFFSET, 0);
|
||||
int limit = params.getFieldInt(field, FacetParams.FACET_LIMIT, 100);
|
||||
if (limit == 0) return new NamedList<>();
|
||||
|
@ -465,13 +482,13 @@ public class SimpleFacets {
|
|||
}
|
||||
|
||||
if (params.getFieldBool(field, GroupParams.GROUP_FACET, false)) {
|
||||
counts = getGroupedCounts(searcher, base, field, multiToken, offset,limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
counts = getGroupedCounts(searcher, docs, field, multiToken, offset,limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
} else {
|
||||
assert method != null;
|
||||
switch (method) {
|
||||
case ENUM:
|
||||
assert TrieField.getMainValuePrefix(ft) == null;
|
||||
counts = getFacetTermEnumCounts(searcher, base, field, offset, limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
counts = getFacetTermEnumCounts(searcher, docs, field, offset, limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
break;
|
||||
case FCS:
|
||||
assert !multiToken;
|
||||
|
@ -483,16 +500,16 @@ public class SimpleFacets {
|
|||
if (contains != null && !contains.isEmpty()) {
|
||||
throw new SolrException(ErrorCode.BAD_REQUEST, FacetParams.FACET_CONTAINS + " is not supported on numeric types");
|
||||
}
|
||||
counts = NumericFacets.getCounts(searcher, base, field, offset, limit, mincount, missing, sort);
|
||||
counts = NumericFacets.getCounts(searcher, docs, field, offset, limit, mincount, missing, sort);
|
||||
} else {
|
||||
PerSegmentSingleValuedFaceting ps = new PerSegmentSingleValuedFaceting(searcher, base, field, offset,limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
PerSegmentSingleValuedFaceting ps = new PerSegmentSingleValuedFaceting(searcher, docs, field, offset, limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
Executor executor = threads == 0 ? directExecutor : facetExecutor;
|
||||
ps.setNumThreads(threads);
|
||||
counts = ps.getFacetCounts(executor);
|
||||
}
|
||||
break;
|
||||
case FC:
|
||||
counts = DocValuesFacets.getCounts(searcher, base, field, offset,limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
counts = DocValuesFacets.getCounts(searcher, docs, field, offset,limit, mincount, missing, sort, prefix, contains, ignoreCase);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
|
@ -598,7 +615,7 @@ public class SimpleFacets {
|
|||
throws IOException, SyntaxError {
|
||||
|
||||
NamedList<Object> res = new SimpleOrderedMap<>();
|
||||
String[] facetFs = params.getParams(FacetParams.FACET_FIELD);
|
||||
String[] facetFs = global.getParams(FacetParams.FACET_FIELD);
|
||||
if (null == facetFs) {
|
||||
return res;
|
||||
}
|
||||
|
@ -614,11 +631,11 @@ public class SimpleFacets {
|
|||
try {
|
||||
//Loop over fields; submit to executor, keeping the future
|
||||
for (String f : facetFs) {
|
||||
parseParams(FacetParams.FACET_FIELD, f);
|
||||
final ParsedParams parsed = parseParams(FacetParams.FACET_FIELD, f);
|
||||
final SolrParams localParams = parsed.localParams;
|
||||
final String termList = localParams == null ? null : localParams.get(CommonParams.TERMS);
|
||||
final String workerKey = key;
|
||||
final String workerFacetValue = facetValue;
|
||||
final DocSet workerBase = this.docs;
|
||||
final String key = parsed.key;
|
||||
final String facetValue = parsed.facetValue;
|
||||
Callable<NamedList> callable = new Callable<NamedList>() {
|
||||
@Override
|
||||
public NamedList call() throws Exception {
|
||||
|
@ -626,16 +643,16 @@ public class SimpleFacets {
|
|||
NamedList<Object> result = new SimpleOrderedMap<>();
|
||||
if(termList != null) {
|
||||
List<String> terms = StrUtils.splitSmart(termList, ",", true);
|
||||
result.add(workerKey, getListedTermCounts(workerFacetValue, workerBase, terms));
|
||||
result.add(key, getListedTermCounts(facetValue, parsed, terms));
|
||||
} else {
|
||||
result.add(workerKey, getTermCounts(workerFacetValue, workerBase));
|
||||
result.add(key, getTermCounts(facetValue, parsed));
|
||||
}
|
||||
return result;
|
||||
} catch (SolrException se) {
|
||||
throw se;
|
||||
} catch (Exception e) {
|
||||
throw new SolrException(ErrorCode.SERVER_ERROR,
|
||||
"Exception during facet.field: " + workerFacetValue, e);
|
||||
"Exception during facet.field: " + facetValue, e);
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
|
@ -668,30 +685,18 @@ public class SimpleFacets {
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Computes the term->count counts for the specified termList relative to the
|
||||
* @param field the name of the field to compute term counts against
|
||||
* @param termList a comma seperated (and backslash escaped) list of term values (in the specified field) to compute the counts for
|
||||
* @see StrUtils#splitSmart
|
||||
*/
|
||||
private NamedList<Integer> getListedTermCounts(String field, String termList) throws IOException {
|
||||
List<String> terms = StrUtils.splitSmart(termList, ",", true);
|
||||
return getListedTermCounts(field, this.docs, terms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the term->count counts for the specified term values relative to the
|
||||
* @param field the name of the field to compute term counts against
|
||||
* @param base the docset to compute term counts relative to
|
||||
* @param parsed contains the docset to compute term counts relative to
|
||||
* @param terms a list of term values (in the specified field) to compute the counts for
|
||||
*/
|
||||
protected NamedList<Integer> getListedTermCounts(String field, DocSet base, List<String> terms) throws IOException {
|
||||
protected NamedList<Integer> getListedTermCounts(String field, final ParsedParams parsed, List<String> terms) throws IOException {
|
||||
FieldType ft = searcher.getSchema().getFieldType(field);
|
||||
NamedList<Integer> res = new NamedList<>();
|
||||
for (String term : terms) {
|
||||
String internal = ft.toInternal(term);
|
||||
int count = searcher.numDocs(new TermQuery(new Term(field, internal)), base);
|
||||
int count = searcher.numDocs(new TermQuery(new Term(field, internal)), parsed.docs);
|
||||
res.add(term, count);
|
||||
}
|
||||
return res;
|
||||
|
@ -731,7 +736,7 @@ public class SimpleFacets {
|
|||
*/
|
||||
|
||||
// Minimum term docFreq in order to use the filterCache for that term.
|
||||
int minDfFilterCache = params.getFieldInt(field, FacetParams.FACET_ENUM_CACHE_MINDF, 0);
|
||||
int minDfFilterCache = global.getFieldInt(field, FacetParams.FACET_ENUM_CACHE_MINDF, 0);
|
||||
|
||||
// make sure we have a set that is fast for random access, if we will use it for that
|
||||
DocSet fastForRandomSet = docs;
|
||||
|
@ -893,7 +898,7 @@ public class SimpleFacets {
|
|||
throws IOException, SyntaxError {
|
||||
|
||||
final NamedList<Object> resOuter = new SimpleOrderedMap<>();
|
||||
final String[] fields = params.getParams(FacetParams.FACET_DATE);
|
||||
final String[] fields = global.getParams(FacetParams.FACET_DATE);
|
||||
|
||||
if (null == fields || 0 == fields.length) return resOuter;
|
||||
|
||||
|
@ -913,9 +918,11 @@ public class SimpleFacets {
|
|||
|
||||
final IndexSchema schema = searcher.getSchema();
|
||||
|
||||
parseParams(FacetParams.FACET_DATE, dateFacet);
|
||||
String f = facetValue;
|
||||
|
||||
final ParsedParams parsed = parseParams(FacetParams.FACET_DATE, dateFacet);
|
||||
final SolrParams params = parsed.params;
|
||||
final SolrParams required = parsed.required;
|
||||
final String key = parsed.key;
|
||||
final String f = parsed.facetValue;
|
||||
|
||||
final NamedList<Object> resInner = new SimpleOrderedMap<>();
|
||||
resOuter.add(key, resInner);
|
||||
|
@ -1000,7 +1007,7 @@ public class SimpleFacets {
|
|||
(include.contains(FacetRangeInclude.UPPER) ||
|
||||
(include.contains(FacetRangeInclude.EDGE) && high.equals(end)));
|
||||
|
||||
final int count = rangeCount(sf,low,high,includeLower,includeUpper);
|
||||
final int count = rangeCount(parsed,sf,low,high,includeLower,includeUpper);
|
||||
if (count >= minCount) {
|
||||
resInner.add(label, count);
|
||||
}
|
||||
|
@ -1036,7 +1043,7 @@ public class SimpleFacets {
|
|||
if (all || others.contains(FacetRangeOther.BEFORE)) {
|
||||
// include upper bound if "outer" or if first gap doesn't already include it
|
||||
resInner.add(FacetRangeOther.BEFORE.toString(),
|
||||
rangeCount(sf,null,start,
|
||||
rangeCount(parsed,sf,null,start,
|
||||
false,
|
||||
(include.contains(FacetRangeInclude.OUTER) ||
|
||||
(! (include.contains(FacetRangeInclude.LOWER) ||
|
||||
|
@ -1045,7 +1052,7 @@ public class SimpleFacets {
|
|||
if (all || others.contains(FacetRangeOther.AFTER)) {
|
||||
// include lower bound if "outer" or if last gap doesn't already include it
|
||||
resInner.add(FacetRangeOther.AFTER.toString(),
|
||||
rangeCount(sf,end,null,
|
||||
rangeCount(parsed,sf,end,null,
|
||||
(include.contains(FacetRangeInclude.OUTER) ||
|
||||
(! (include.contains(FacetRangeInclude.UPPER) ||
|
||||
include.contains(FacetRangeInclude.EDGE)))),
|
||||
|
@ -1053,7 +1060,7 @@ public class SimpleFacets {
|
|||
}
|
||||
if (all || others.contains(FacetRangeOther.BETWEEN)) {
|
||||
resInner.add(FacetRangeOther.BETWEEN.toString(),
|
||||
rangeCount(sf,start,end,
|
||||
rangeCount(parsed,sf,start,end,
|
||||
(include.contains(FacetRangeInclude.LOWER) ||
|
||||
include.contains(FacetRangeInclude.EDGE)),
|
||||
(include.contains(FacetRangeInclude.UPPER) ||
|
||||
|
@ -1074,7 +1081,7 @@ public class SimpleFacets {
|
|||
|
||||
public NamedList<Object> getFacetRangeCounts() throws IOException, SyntaxError {
|
||||
final NamedList<Object> resOuter = new SimpleOrderedMap<>();
|
||||
final String[] fields = params.getParams(FacetParams.FACET_RANGE);
|
||||
final String[] fields = global.getParams(FacetParams.FACET_RANGE);
|
||||
|
||||
if (null == fields || 0 == fields.length) return resOuter;
|
||||
|
||||
|
@ -1090,11 +1097,12 @@ public class SimpleFacets {
|
|||
|
||||
final IndexSchema schema = searcher.getSchema();
|
||||
|
||||
parseParams(FacetParams.FACET_RANGE, facetRange);
|
||||
String f = facetValue;
|
||||
String methodStr = params.get(FacetParams.FACET_RANGE_METHOD);
|
||||
final ParsedParams parsed = parseParams(FacetParams.FACET_RANGE, facetRange);
|
||||
final String key = parsed.key;
|
||||
final String f = parsed.facetValue;
|
||||
String methodStr = parsed.params.get(FacetParams.FACET_RANGE_METHOD);
|
||||
FacetRangeMethod method = (methodStr==null?FacetRangeMethod.getDefault():FacetRangeMethod.get(methodStr));
|
||||
boolean groupFacet = params.getBool(GroupParams.GROUP_FACET, false);
|
||||
boolean groupFacet = parsed.params.getBool(GroupParams.GROUP_FACET, false);
|
||||
if (groupFacet && method.equals(FacetRangeMethod.DV)) {
|
||||
// the user has explicitly selected the FacetRangeMethod.DV method
|
||||
log.warn("Range facet method '" + FacetRangeMethod.DV + "' is not supported together with '" +
|
||||
|
@ -1146,17 +1154,20 @@ public class SimpleFacets {
|
|||
}
|
||||
if (method.equals(FacetRangeMethod.DV)) {
|
||||
assert ft instanceof TrieField;
|
||||
resOuter.add(key, getFacetRangeCountsDocValues(sf, calc));
|
||||
resOuter.add(key, getFacetRangeCountsDocValues(sf, calc, parsed));
|
||||
} else {
|
||||
resOuter.add(key, getFacetRangeCounts(sf, calc));
|
||||
resOuter.add(key, getFacetRangeCounts(sf, calc, parsed));
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Comparable<T>> NamedList<Object> getFacetRangeCounts
|
||||
(final SchemaField sf,
|
||||
final RangeEndpointCalculator<T> calc) throws IOException {
|
||||
final RangeEndpointCalculator<T> calc,
|
||||
final ParsedParams parsed) throws IOException {
|
||||
|
||||
final String f = sf.getName();
|
||||
final SolrParams params = parsed.params;
|
||||
final SolrParams required = parsed.required;
|
||||
final NamedList<Object> res = new SimpleOrderedMap<>();
|
||||
final NamedList<Integer> counts = new NamedList<>();
|
||||
res.add("counts", counts);
|
||||
|
@ -1214,7 +1225,7 @@ public class SimpleFacets {
|
|||
final String lowS = calc.formatValue(low);
|
||||
final String highS = calc.formatValue(high);
|
||||
|
||||
final int count = rangeCount(sf, lowS, highS,
|
||||
final int count = rangeCount(parsed, sf, lowS, highS,
|
||||
includeLower,includeUpper);
|
||||
if (count >= minCount) {
|
||||
counts.add(lowS, count);
|
||||
|
@ -1249,7 +1260,7 @@ public class SimpleFacets {
|
|||
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,
|
||||
rangeCount(parsed,sf,null,startS,
|
||||
false,
|
||||
(include.contains(FacetRangeInclude.OUTER) ||
|
||||
(! (include.contains(FacetRangeInclude.LOWER) ||
|
||||
|
@ -1259,7 +1270,7 @@ public class SimpleFacets {
|
|||
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,
|
||||
rangeCount(parsed,sf,endS,null,
|
||||
(include.contains(FacetRangeInclude.OUTER) ||
|
||||
(! (include.contains(FacetRangeInclude.UPPER) ||
|
||||
include.contains(FacetRangeInclude.EDGE)))),
|
||||
|
@ -1267,7 +1278,7 @@ public class SimpleFacets {
|
|||
}
|
||||
if (all || others.contains(FacetRangeOther.BETWEEN)) {
|
||||
res.add(FacetRangeOther.BETWEEN.toString(),
|
||||
rangeCount(sf,startS,endS,
|
||||
rangeCount(parsed,sf,startS,endS,
|
||||
(include.contains(FacetRangeInclude.LOWER) ||
|
||||
include.contains(FacetRangeInclude.EDGE)),
|
||||
(include.contains(FacetRangeInclude.UPPER) ||
|
||||
|
@ -1280,15 +1291,15 @@ public class SimpleFacets {
|
|||
}
|
||||
|
||||
private <T extends Comparable<T>> NamedList<Object> getFacetRangeCountsDocValues(final SchemaField sf,
|
||||
final RangeEndpointCalculator<T> calc) throws IOException {
|
||||
final RangeEndpointCalculator<T> calc, ParsedParams parsed) throws IOException {
|
||||
|
||||
final String f = sf.getName();
|
||||
final NamedList<Object> res = new SimpleOrderedMap<>();
|
||||
final NamedList<Integer> counts = new NamedList<>();
|
||||
res.add("counts", counts);
|
||||
|
||||
String globalStartS = required.getFieldParam(f,FacetParams.FACET_RANGE_START);
|
||||
String globalEndS = required.getFieldParam(f,FacetParams.FACET_RANGE_END);
|
||||
String globalStartS = parsed.required.getFieldParam(f,FacetParams.FACET_RANGE_START);
|
||||
String globalEndS = parsed.required.getFieldParam(f,FacetParams.FACET_RANGE_END);
|
||||
|
||||
final T start = calc.getValue(globalStartS);
|
||||
// not final, hardend may change this
|
||||
|
@ -1299,19 +1310,19 @@ public class SimpleFacets {
|
|||
"range facet 'end' comes before 'start': "+end+" < "+start);
|
||||
}
|
||||
|
||||
final String gap = required.getFieldParam(f, FacetParams.FACET_RANGE_GAP);
|
||||
final String gap = parsed.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 int minCount = parsed.params.getFieldInt(f,FacetParams.FACET_MINCOUNT, 0);
|
||||
|
||||
final EnumSet<FacetRangeInclude> include = FacetRangeInclude.parseParam
|
||||
(params.getFieldParams(f,FacetParams.FACET_RANGE_INCLUDE));
|
||||
(parsed.params.getFieldParams(f,FacetParams.FACET_RANGE_INCLUDE));
|
||||
ArrayList<IntervalFacets.FacetInterval> intervals = new ArrayList<>();
|
||||
|
||||
final String[] othersP =
|
||||
params.getFieldParams(f,FacetParams.FACET_RANGE_OTHER);
|
||||
parsed.params.getFieldParams(f,FacetParams.FACET_RANGE_OTHER);
|
||||
|
||||
boolean includeBefore = false;
|
||||
boolean includeBetween = false;
|
||||
|
@ -1353,7 +1364,7 @@ public class SimpleFacets {
|
|||
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)) {
|
||||
if (parsed.params.getFieldBool(f,FacetParams.FACET_RANGE_HARD_END,false)) {
|
||||
high = end;
|
||||
} else {
|
||||
end = high;
|
||||
|
@ -1418,7 +1429,7 @@ public class SimpleFacets {
|
|||
// don't use the ArrayList anymore
|
||||
intervals = null;
|
||||
|
||||
new IntervalFacets(sf, searcher, docs, intervalsArray);
|
||||
new IntervalFacets(sf, searcher, parsed.docs, intervalsArray);
|
||||
|
||||
int intervalIndex = 0;
|
||||
int lastIntervalIndex = intervalsArray.length - 1;
|
||||
|
@ -1461,13 +1472,13 @@ public class SimpleFacets {
|
|||
* @see SolrIndexSearcher#numDocs
|
||||
* @see TermRangeQuery
|
||||
*/
|
||||
protected int rangeCount(SchemaField sf, String low, String high,
|
||||
protected int rangeCount(ParsedParams parsed, SchemaField sf, String low, String high,
|
||||
boolean iLow, boolean iHigh) throws IOException {
|
||||
Query rangeQ = sf.getType().getRangeQuery(null, sf, low, high, iLow, iHigh);
|
||||
if (params.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
return getGroupedFacetQueryCount(rangeQ);
|
||||
if (parsed.params.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
return getGroupedFacetQueryCount(rangeQ, parsed);
|
||||
} else {
|
||||
return searcher.numDocs(rangeQ , docs);
|
||||
return searcher.numDocs(rangeQ , parsed.docs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1475,10 +1486,10 @@ public class SimpleFacets {
|
|||
* @deprecated Use rangeCount(SchemaField,String,String,boolean,boolean) which is more generalized
|
||||
*/
|
||||
@Deprecated
|
||||
protected int rangeCount(SchemaField sf, Date low, Date high,
|
||||
protected int rangeCount(ParsedParams parsed, SchemaField sf, Date low, Date high,
|
||||
boolean iLow, boolean iHigh) throws IOException {
|
||||
Query rangeQ = ((TrieDateField)(sf.getType())).getRangeQuery(null, sf, low, high, iLow, iHigh);
|
||||
return searcher.numDocs(rangeQ, docs);
|
||||
return searcher.numDocs(rangeQ, parsed.docs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1731,20 +1742,20 @@ public class SimpleFacets {
|
|||
*/
|
||||
public NamedList<Object> getFacetIntervalCounts() throws IOException, SyntaxError {
|
||||
NamedList<Object> res = new SimpleOrderedMap<Object>();
|
||||
String[] fields = params.getParams(FacetParams.FACET_INTERVAL);
|
||||
String[] fields = global.getParams(FacetParams.FACET_INTERVAL);
|
||||
if (fields == null || fields.length == 0) return res;
|
||||
|
||||
for (String field : fields) {
|
||||
parseParams(FacetParams.FACET_INTERVAL, field);
|
||||
String[] intervalStrs = required.getFieldParams(facetValue, FacetParams.FACET_INTERVAL_SET);
|
||||
SchemaField schemaField = searcher.getCore().getLatestSchema().getField(facetValue);
|
||||
if (params.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
final ParsedParams parsed = parseParams(FacetParams.FACET_INTERVAL, field);
|
||||
String[] intervalStrs = parsed.required.getFieldParams(parsed.facetValue, FacetParams.FACET_INTERVAL_SET);
|
||||
SchemaField schemaField = searcher.getCore().getLatestSchema().getField(parsed.facetValue);
|
||||
if (parsed.params.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Interval Faceting can't be used with " + GroupParams.GROUP_FACET);
|
||||
}
|
||||
|
||||
SimpleOrderedMap<Integer> fieldResults = new SimpleOrderedMap<Integer>();
|
||||
res.add(key, fieldResults);
|
||||
IntervalFacets intervalFacets = new IntervalFacets(schemaField, searcher, docs, intervalStrs, params);
|
||||
res.add(parsed.key, fieldResults);
|
||||
IntervalFacets intervalFacets = new IntervalFacets(schemaField, searcher, parsed.docs, intervalStrs, parsed.params);
|
||||
for (FacetInterval interval : intervalFacets) {
|
||||
fieldResults.add(interval.getKey(), interval.getCount());
|
||||
}
|
||||
|
@ -1759,14 +1770,14 @@ public class SimpleFacets {
|
|||
if (unparsedFields == null || unparsedFields.length == 0) {
|
||||
return resOuter;
|
||||
}
|
||||
if (params.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
if (global.getBool(GroupParams.GROUP_FACET, false)) {
|
||||
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
|
||||
"Heatmaps can't be used with " + GroupParams.GROUP_FACET);
|
||||
}
|
||||
for (String unparsedField : unparsedFields) {
|
||||
parseParams(FacetParams.FACET_HEATMAP, unparsedField); // populates facetValue, rb, params, docs
|
||||
final ParsedParams parsed = parseParams(FacetParams.FACET_HEATMAP, unparsedField); // populates facetValue, rb, params, docs
|
||||
|
||||
resOuter.add(key, SpatialHeatmapFacets.getHeatmapForField(key, facetValue, rb, params, docs));
|
||||
resOuter.add(parsed.key, SpatialHeatmapFacets.getHeatmapForField(parsed.key, parsed.facetValue, rb, parsed.params, parsed.docs));
|
||||
}
|
||||
return resOuter;
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
}
|
||||
|
||||
static void indexSimpleFacetCounts() {
|
||||
add_doc("id", "42",
|
||||
add_doc("id", "42",
|
||||
"range_facet_f", "35.3",
|
||||
"range_facet_f1", "35.3",
|
||||
"trait_s", "Tool", "trait_s", "Obnoxious",
|
||||
|
@ -127,7 +127,7 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"range_facet_mv_f", "7.5",
|
||||
"range_facet_mv_f", "12.0"
|
||||
);
|
||||
add_doc("id", "44",
|
||||
add_doc("id", "44",
|
||||
"range_facet_f", "15.97",
|
||||
"range_facet_f1", "15.97",
|
||||
"trait_s", "Tool",
|
||||
|
@ -137,7 +137,7 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"range_facet_mv_f", "5",
|
||||
"range_facet_mv_f", "74"
|
||||
);
|
||||
add_doc("id", "45",
|
||||
add_doc("id", "45",
|
||||
"range_facet_f", "30.0",
|
||||
"range_facet_f1", "30.0",
|
||||
"trait_s", "Chauvinist",
|
||||
|
@ -148,7 +148,7 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"range_facet_mv_f", "32.77",
|
||||
"range_facet_mv_f", "0.123"
|
||||
);
|
||||
add_doc("id", "46",
|
||||
add_doc("id", "46",
|
||||
"range_facet_f", "20.0",
|
||||
"range_facet_f1", "20.0",
|
||||
"trait_s", "Obnoxious",
|
||||
|
@ -159,14 +159,16 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"range_facet_mv_f", "7.3",
|
||||
"range_facet_mv_f", "0.123"
|
||||
);
|
||||
add_doc("id", "47",
|
||||
"range_facet_f", "28.62",
|
||||
"range_facet_f1", "28.62",
|
||||
add_doc("id", "47",
|
||||
"range_facet_f", "28.62",
|
||||
"range_facet_f1", "28.62",
|
||||
"trait_s", "Pig",
|
||||
"text", "line up and fly directly at the enemy death cannons, clogging them with wreckage!",
|
||||
"zerolen_s","",
|
||||
"foo_s","A", "foo_s","B", "foo_s","C"
|
||||
);
|
||||
add_doc("id", "101", "myfield_s", "foo");
|
||||
add_doc("id", "102", "myfield_s", "bar");
|
||||
}
|
||||
|
||||
static void indexSimpleGroupedFacetCounts() {
|
||||
|
@ -388,7 +390,7 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"group.facet", "true",
|
||||
"group.field", "hotel_s1",
|
||||
"facet", "true",
|
||||
"facet.limit", facetLimit,
|
||||
"facet.limit", facetLimit,
|
||||
"facet.field", "airport_s1"
|
||||
),
|
||||
"//lst[@name='facet_fields']/lst[@name='airport_s1']",
|
||||
|
@ -405,8 +407,8 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"group.facet", "true",
|
||||
"group.field", "hotel_s1",
|
||||
"facet", "true",
|
||||
"facet.offset", "1",
|
||||
"facet.limit", facetLimit,
|
||||
"facet.offset", "1",
|
||||
"facet.limit", facetLimit,
|
||||
"facet.field", "airport_s1"
|
||||
),
|
||||
"//lst[@name='facet_fields']/lst[@name='airport_s1']",
|
||||
|
@ -423,7 +425,7 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"group.facet", "true",
|
||||
"group.field", "hotel_s1",
|
||||
"facet", "true",
|
||||
"facet.limit", facetLimit,
|
||||
"facet.limit", facetLimit,
|
||||
"facet.field", "airport_s1"
|
||||
),
|
||||
"//lst[@name='facet_fields']/lst[@name='airport_s1']",
|
||||
|
@ -441,7 +443,7 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
"group.field", "hotel_s1",
|
||||
"facet", "true",
|
||||
"facet.field", "airport_s1",
|
||||
"facet.limit", facetLimit,
|
||||
"facet.limit", facetLimit,
|
||||
"facet.prefix", "a"
|
||||
),
|
||||
"//lst[@name='facet_fields']/lst[@name='airport_s1']",
|
||||
|
@ -2882,6 +2884,19 @@ public class SimpleFacetsTest extends SolrTestCaseJ4 {
|
|||
|
||||
}
|
||||
|
||||
public void testFacetPrefixWithFacetThreads() throws Exception {
|
||||
assertQ("Test facet.prefix with facet.thread",
|
||||
req("q", "id:[101 TO 102]"
|
||||
,"facet","true"
|
||||
,"facet.field", "{!key=key1 facet.prefix=foo}myfield_s"
|
||||
,"facet.field", "{!key=key2 facet.prefix=bar}myfield_s"
|
||||
,"facet.threads", "1"
|
||||
)
|
||||
,"*[count(//lst[@name='facet_fields']/lst[@name='key1']/int[@name='foo'])=1]"
|
||||
,"*[count(//lst[@name='facet_fields']/lst[@name='key2']/int[@name='bar'])=1]"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private String getRandomQuery() {
|
||||
if (rarely()) {
|
||||
|
|
Loading…
Reference in New Issue