mirror of https://github.com/apache/lucene.git
SOLR-7452: refinement of missing buckets and partial facets through missing buckets
This commit is contained in:
parent
e80643e5a7
commit
cc623403bd
|
@ -18,8 +18,11 @@
|
|||
package org.apache.solr.search.facet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.solr.common.util.SimpleOrderedMap;
|
||||
|
@ -167,7 +170,29 @@ public class FacetFieldMerger extends FacetRequestSortedMerger<FacetField> {
|
|||
// basically , only do at the top-level facet?
|
||||
}
|
||||
|
||||
@Override
|
||||
Map<String, Object> getRefinementSpecial(Context mcontext, Map<String, Object> refinement, Collection<String> tagsWithPartial) {
|
||||
if (!tagsWithPartial.isEmpty()) {
|
||||
// Since special buckets missing and allBuckets themselves will always be included, we only need to worry about subfacets being partial.
|
||||
if (freq.missing) {
|
||||
refinement = getRefinementSpecial(mcontext, refinement, tagsWithPartial, missingBucket, "missing");
|
||||
}
|
||||
if (freq.allBuckets) {
|
||||
refinement = getRefinementSpecial(mcontext, refinement, tagsWithPartial, allBuckets, "allBuckets");
|
||||
}
|
||||
}
|
||||
return refinement;
|
||||
}
|
||||
|
||||
private Map<String, Object> getRefinementSpecial(Context mcontext, Map<String, Object> refinement, Collection<String> tagsWithPartial, FacetBucket bucket, String label) {
|
||||
// boolean prev = mcontext.setBucketWasMissing(true); // the special buckets should have the same "missing" status as this facet, so no need to set it again
|
||||
Map<String, Object> bucketRefinement = bucket.getRefinement(mcontext, tagsWithPartial);
|
||||
if (bucketRefinement != null) {
|
||||
refinement = refinement == null ? new HashMap<>(2) : refinement;
|
||||
refinement.put(label, bucketRefinement);
|
||||
}
|
||||
return refinement;
|
||||
}
|
||||
|
||||
private static class FacetNumBucketsMerger extends FacetMerger {
|
||||
long sumBuckets;
|
||||
|
|
|
@ -36,6 +36,8 @@ import org.apache.solr.schema.FieldType;
|
|||
import org.apache.solr.schema.SchemaField;
|
||||
import org.apache.solr.search.DocSet;
|
||||
|
||||
import static org.apache.solr.search.facet.FacetContext.SKIP_FACET;
|
||||
|
||||
/**
|
||||
* Facet processing based on field values. (not range nor by query)
|
||||
* @see FacetField
|
||||
|
@ -528,6 +530,9 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
|
|||
}
|
||||
|
||||
protected SimpleOrderedMap<Object> refineFacets() throws IOException {
|
||||
boolean skipThisFacet = (fcontext.flags & SKIP_FACET) != 0;
|
||||
|
||||
|
||||
List leaves = asList(fcontext.facetInfo.get("_l")); // We have not seen this bucket: do full faceting for this bucket, including all sub-facets
|
||||
List<List> skip = asList(fcontext.facetInfo.get("_s")); // We have seen this bucket, so skip stats on it, and skip sub-facets except for the specified sub-facets that should calculate specified buckets.
|
||||
List<List> partial = asList(fcontext.facetInfo.get("_p")); // We have not seen this bucket, do full faceting for this bucket, and most sub-facets... but some sub-facets are partial and should only visit specified buckets.
|
||||
|
@ -563,6 +568,15 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
|
|||
bucketList.add( refineBucket(bucketVal, false, facetInfo ) );
|
||||
}
|
||||
|
||||
if (freq.missing) {
|
||||
Map<String,Object> bucketFacetInfo = (Map<String,Object>)fcontext.facetInfo.get("missing");
|
||||
|
||||
if (bucketFacetInfo != null || !skipThisFacet) {
|
||||
SimpleOrderedMap<Object> missingBucket = new SimpleOrderedMap<>();
|
||||
fillBucket(missingBucket, getFieldMissingQuery(fcontext.searcher, freq.field), null, skipThisFacet, bucketFacetInfo);
|
||||
res.add("missing", missingBucket);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are just a couple of leaves, and if the domain is large, then
|
||||
// going by term is likely the most efficient?
|
||||
|
|
|
@ -240,6 +240,14 @@ abstract class FacetRequestSortedMerger<FacetRequestT extends FacetRequestSorted
|
|||
if (skipBuckets != null) refinement.put("_s", skipBuckets);
|
||||
}
|
||||
|
||||
refinement = getRefinementSpecial(mcontext, refinement, tagsWithPartial);
|
||||
|
||||
return refinement;
|
||||
}
|
||||
|
||||
// utility method for subclasses to override to finish calculating faceting (special buckets in field facets)... this feels hacky and we
|
||||
// should find a better way.
|
||||
Map<String,Object> getRefinementSpecial(Context mcontext, Map<String,Object> refinement, Collection<String> tagsWithPartial) {
|
||||
return refinement;
|
||||
}
|
||||
|
||||
|
|
|
@ -219,6 +219,17 @@ public class TestJsonFacetRefinement extends SolrTestCaseHS {
|
|||
"}"
|
||||
);
|
||||
|
||||
// test partial _p under a missing bucket
|
||||
doTestRefine("{top:{type:terms, field:Afield, refine:true, limit:1, missing:true, facet:{x : {type:terms, field:X, limit:1, refine:true} } } }",
|
||||
"{top: {buckets:[], missing:{count:12, x:{buckets:[{val:x2, count:4},{val:x3, count:2}]} } } }",
|
||||
"{top: {buckets:[], missing:{count:10, x:{buckets:[{val:x1, count:5},{val:x4, count:3}]} } } }",
|
||||
"=={top: {" +
|
||||
"missing:{x:{_l:[x1]}}" +
|
||||
" } " +
|
||||
"}"
|
||||
, null
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -266,6 +277,17 @@ public class TestJsonFacetRefinement extends SolrTestCaseHS {
|
|||
);
|
||||
****/
|
||||
|
||||
// test refining under the special "missing" bucket of a field facet
|
||||
client.testJQ(params(p, "q", "*:*",
|
||||
"json.facet", "{" +
|
||||
"f:{type:terms, field:missing_s, limit:1, overrequest:0, missing:true, refine:true, facet:{ cat:{type:terms, field:${cat_s}, limit:1, overrequest:0, refine:true } }}" +
|
||||
"}"
|
||||
)
|
||||
, "facets=={ count:8" +
|
||||
", f:{ buckets:[], missing:{count:8, cat:{buckets:[{val:A,count:4}]} } }" + // just like the previous response, just nested under a field facet
|
||||
"}"
|
||||
);
|
||||
|
||||
|
||||
client.testJQ(params(p, "q", "*:*",
|
||||
"json.facet", "{" +
|
||||
|
@ -317,7 +339,7 @@ public class TestJsonFacetRefinement extends SolrTestCaseHS {
|
|||
"}"
|
||||
);
|
||||
|
||||
// test missing buckets (field facet within field facet)
|
||||
// test partial buckets (field facet within field facet)
|
||||
client.testJQ(params(p, "q", "*:*",
|
||||
"json.facet", "{" +
|
||||
"ab:{type:terms, field:${cat_s}, limit:1, overrequest:0, refine:true, facet:{ xy:{type:terms, field:${xy_s}, limit:1, overrequest:0, refine:true } }}" +
|
||||
|
@ -345,6 +367,8 @@ public class TestJsonFacetRefinement extends SolrTestCaseHS {
|
|||
"}"
|
||||
);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue