diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 1fc4587f3e0..24af20e8f7e 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -249,6 +249,8 @@ Bug Fixes * SOLR-10520: child.facet.field doubled counts at least when rows>0. (Dr. Oleg Savrasov via Mikhail Khludnev) +* SOLR-10480: Full pagination in JSON Facet API using offset does not work. (yonik) + Other Changes ---------------------- diff --git a/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessor.java b/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessor.java index e9fb0793167..143d1fce026 100644 --- a/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessor.java +++ b/solr/core/src/java/org/apache/solr/search/facet/FacetFieldProcessor.java @@ -217,9 +217,11 @@ abstract class FacetFieldProcessor extends FacetProcessor { if (freq.limit >= 0) { effectiveLimit = freq.limit; if (fcontext.isShard()) { - // add over-request if this is a shard request if (freq.overrequest == -1) { - effectiveLimit = (long) (effectiveLimit*1.1+4); // default: add 10% plus 4 (to overrequest for very small limits) + // add over-request if this is a shard request and if we have a small offset (large offsets will already be gathering many more buckets than needed) + if (freq.offset < 10) { + effectiveLimit = (long) (effectiveLimit * 1.1 + 4); // default: add 10% plus 4 (to overrequest for very small limits) + } } else { effectiveLimit += freq.overrequest; } @@ -229,7 +231,7 @@ abstract class FacetFieldProcessor extends FacetProcessor { final int sortMul = freq.sortDirection.getMultiplier(); - int maxTopVals = (int) (effectiveLimit >= 0 ? Math.min(off + effectiveLimit, Integer.MAX_VALUE - 1) : Integer.MAX_VALUE - 1); + int maxTopVals = (int) (effectiveLimit >= 0 ? Math.min(freq.offset + effectiveLimit, Integer.MAX_VALUE - 1) : Integer.MAX_VALUE - 1); maxTopVals = Math.min(maxTopVals, slotCardinality); final SlotAcc sortAcc = this.sortAcc, indexOrderAcc = this.indexOrderAcc; final BiPredicate orderPredicate; @@ -315,7 +317,7 @@ abstract class FacetFieldProcessor extends FacetProcessor { // if we are deep paging, we don't have to order the highest "offset" counts. int collectCount = Math.max(0, queue.size() - off); - assert collectCount <= effectiveLimit; + assert collectCount <= maxTopVals; int[] sortedSlots = new int[collectCount]; for (int i = collectCount - 1; i >= 0; i--) { sortedSlots[i] = queue.pop().slot; diff --git a/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java b/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java index a8a1eaab5b9..a2b6f0695de 100644 --- a/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java +++ b/solr/core/src/test/org/apache/solr/search/facet/TestJsonFacets.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Random; @@ -1314,6 +1315,10 @@ public class TestJsonFacets extends SolrTestCaseHS { doBigger( client, p ); } + private String getId(int id) { + return String.format(Locale.US, "%05d", id); + } + public void doBigger(Client client, ModifiableSolrParams p) throws Exception { MacroExpander m = new MacroExpander(p.getMap()); @@ -1332,7 +1337,7 @@ public class TestJsonFacets extends SolrTestCaseHS { for (int i=0; i> sub = model.get(cat); if (sub == null) { sub = new HashMap<>(); @@ -1371,6 +1376,23 @@ public class TestJsonFacets extends SolrTestCaseHS { ); } + client.testJQ(params(p, "q", "*:*" + , "json.facet", "{f1:{type:terms, field:id, limit:1, offset:990}}" + ) + , "facets=={ 'count':" + ndocs + "," + + "'f1':{buckets:[{val:'00990',count:1}]}} " + ); + + + for (int i=0; i<20; i++) { + int off = random().nextInt(ndocs); + client.testJQ(params(p, "q", "*:*", "off",Integer.toString(off) + , "json.facet", "{f1:{type:terms, field:id, limit:1, offset:${off}}}" + ) + , "facets=={ 'count':" + ndocs + "," + + "'f1':{buckets:[{val:'" + getId(off) + "',count:1}]}} " + ); + } } public void testTolerant() throws Exception {