SOLR-9681: add filters to any facet command

This commit is contained in:
yonik 2016-10-29 14:16:27 -04:00
parent 2e21511cd3
commit 650276e14b
4 changed files with 74 additions and 2 deletions

View File

@ -79,6 +79,13 @@ Jetty 9.3.8.v20160314
Detailed Change List
----------------------
New Features
----------------------
* SOLR-9681: FacetModule / JSON Facet API added the ability to add filters directly to
any facet command. The filters are applied after any domain change operations.
Example: { type:terms, field:category, filter:"user:yonik" }
(yonik)
Other Changes
----------------------

View File

@ -50,11 +50,13 @@ public abstract class FacetProcessor<FacetRequestT extends FacetRequest> {
FacetContext fcontext;
FacetRequestT freq;
DocSet filter; // additional filters specified by "filter" // TODO: do these need to be on the context to support recomputing during multi-select?
LinkedHashMap<String,SlotAcc> accMap;
SlotAcc[] accs;
CountSlotAcc countAcc;
/** factory method for invoking json facet framework as whole */
/** factory method for invoking json facet framework as whole.
* Note: this is currently only used from SimpleFacets, not from JSON Facet API itself. */
public static FacetProcessor<?> createProcessor(SolrQueryRequest req,
Map<String, Object> params, DocSet docs){
FacetParser parser = new FacetTopParser(req);
@ -84,7 +86,38 @@ public abstract class FacetProcessor<FacetRequestT extends FacetRequest> {
}
public void process() throws IOException {
// Check filters... if we do have filters they apply after domain changes.
// We still calculate them first because we can use it in a parent->child domain change.
handleFilters();
handleDomainChanges();
if (filter != null) {
fcontext.base = fcontext.base.intersection( filter );
}
}
private void handleFilters() throws IOException {
if (freq.filters == null || freq.filters.isEmpty()) return;
List<Query> qlist = new ArrayList<>(freq.filters.size());
// TODO: prevent parsing filters each time!
for (Object rawFilter : freq.filters) {
Query symbolicFilter;
if (rawFilter instanceof String) {
QParser parser = null;
try {
parser = QParser.getParser((String)rawFilter, fcontext.req);
symbolicFilter = parser.getQuery();
} catch (SyntaxError syntaxError) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, syntaxError);
}
} else {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Bad query (expected a string):" + rawFilter);
}
qlist.add(symbolicFilter);
}
this.filter = fcontext.searcher.getDocSet(qlist);
}
private void handleDomainChanges() throws IOException {

View File

@ -16,6 +16,7 @@
*/
package org.apache.solr.search.facet;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
@ -77,7 +78,7 @@ public abstract class FacetRequest {
protected Map<String,AggValueSource> facetStats; // per-bucket statistics
protected Map<String,FacetRequest> subFacets; // per-bucket sub-facets
protected List<String> filters;
protected List<Object> filters;
protected boolean processEmpty;
protected Domain domain;
@ -376,6 +377,16 @@ abstract class FacetParser<FacetRequestT extends FacetRequest> {
}
Object filterOrList = m.get("filter");
if (filterOrList != null) {
if (filterOrList instanceof List) {
facet.filters = (List<Object>)filterOrList;
} else {
facet.filters = new ArrayList<>(1);
facet.filters.add(filterOrList);
}
}
}
}

View File

@ -1164,6 +1164,27 @@ public class TestJsonFacets extends SolrTestCaseHS {
);
// test filter
client.testJQ(params(p, "q", "*:*", "myfilt","${cat_s}:A"
, "json.facet", "{" +
"t:{${terms} type:terms, field:${cat_s}, filter:[]}" + // empty filter list
",t_filt:{${terms} type:terms, field:${cat_s}, filter:'${cat_s}:B'}" +
",t_filt2:{${terms} type:terms, field:${cat_s}, filter:'{!query v=$myfilt}'}" + // test access to qparser and other query parameters
",t_filt3:{${terms} type:terms, field:${cat_s}, filter:['-id:1','-id:2']}" +
",q:{type:query, q:'${cat_s}:B', filter:['-id:5']}" + // also tests a top-level negative filter
",r:{type:range, field:${num_d}, start:-5, end:10, gap:5, filter:'-id:4'}" +
"}"
)
, "facets=={ count:6, " +
"t :{ buckets:[ {val:B, count:3}, {val:A, count:2} ] }" +
",t_filt :{ buckets:[ {val:B, count:3}] } " +
",t_filt2:{ buckets:[ {val:A, count:2}] } " +
",t_filt3:{ buckets:[ {val:B, count:2}, {val:A, count:1}] } " +
",q:{count:2}" +
",r:{buckets:[ {val:-5.0,count:1}, {val:0.0,count:1}, {val:5.0,count:0} ] }" +
"}"
);
}
@Test