SOLR-11775: return long val for facet count in json facet

* Long value is returned for any count related to json facets
  irrespective of number of shards
This commit is contained in:
Munendra S N 2020-04-10 19:16:54 +05:30
parent 71d335ff68
commit 36b280bd0a
34 changed files with 293 additions and 167 deletions

View File

@ -579,11 +579,11 @@ public class SimpleFacets {
List<NamedList<Object>> buckets = (List<NamedList<Object>>)res.get("buckets");
for(NamedList<Object> b : buckets) {
counts.add(b.get("val").toString(), (Integer)b.get("count"));
counts.add(b.get("val").toString(), ((Number)b.get("count")).intValue());
}
if(missing) {
NamedList<Object> missingCounts = (NamedList<Object>) res.get("missing");
counts.add(null, (Integer)missingCounts.get("count"));
counts.add(null, ((Number)missingCounts.get("count")).intValue());
}
}
break;

View File

@ -50,7 +50,7 @@ public abstract class AggValueSource extends ValueSource {
}
// TODO: make abstract
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
throw new UnsupportedOperationException("NOT IMPLEMENTED " + name + " " + this);
}

View File

@ -37,7 +37,7 @@ public class AvgAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {

View File

@ -24,7 +24,7 @@ public class CountAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
return new CountSlotArrAcc(fcontext, numSlots);
}

View File

@ -37,7 +37,7 @@ public class CountValsAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {
String field = ((FieldNameValueSource)vs).getFieldName();

View File

@ -108,7 +108,7 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
/** This is used to create accs for second phase (or to create accs for all aggs) */
@Override
protected void createAccs(int docCount, int slotCount) throws IOException {
protected void createAccs(long docCount, int slotCount) throws IOException {
if (accMap == null) {
accMap = new LinkedHashMap<>();
}
@ -295,7 +295,7 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
IntFunction<Comparable> bucketValFromSlotNumFunc,
Function<Comparable, String> fieldQueryValFunc) throws IOException {
assert this.sortAcc != null;
int numBuckets = 0;
long numBuckets = 0;
final int off = fcontext.isShard() ? 0 : (int) freq.offset;
@ -347,7 +347,7 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
// screen out buckets not matching mincount
if (effectiveMincount > 0) {
int count = countAcc.getCount(slotNum);
long count = countAcc.getCount(slotNum);
if (count < effectiveMincount) {
if (count > 0)
numBuckets++; // Still increment numBuckets as long as we have some count. This is for consistency between distrib and non-distrib mode.
@ -387,7 +387,7 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
}
FacetDebugInfo fdebug = fcontext.getDebugInfo();
if (fdebug != null) fdebug.putInfoItem("numBuckets", (long) numBuckets);
if (fdebug != null) fdebug.putInfoItem("numBuckets", numBuckets);
if (freq.allBuckets) {
SimpleOrderedMap<Object> allBuckets = new SimpleOrderedMap<>();
@ -507,7 +507,7 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
/** Helper method used solely when looping over buckets to be returned in findTopSlots */
private void fillBucketFromSlot(SimpleOrderedMap<Object> target, Slot slot,
SlotAcc resortAcc) throws IOException {
final int count = countAcc.getCount(slot.slot);
final long count = countAcc.getCount(slot.slot);
target.add("count", count);
if (count <= 0 && !freq.processEmpty) return;
@ -645,14 +645,14 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
}
@Override
protected void processStats(SimpleOrderedMap<Object> bucket, Query bucketQ, DocSet docs, int docCount) throws IOException {
protected void processStats(SimpleOrderedMap<Object> bucket, Query bucketQ, DocSet docs, long docCount) throws IOException {
if (docCount == 0 && !freq.processEmpty || freq.getFacetStats().size() == 0) {
bucket.add("count", docCount);
return;
}
createAccs(docCount, 1);
assert null != bucketQ;
int collected = collect(docs, 0, slotNum -> { return new SlotContext(bucketQ); });
long collected = collect(docs, 0, slotNum -> { return new SlotContext(bucketQ); });
// countAcc.incrementCount(0, collected); // should we set the counton the acc instead of just passing it?
@ -661,7 +661,7 @@ abstract class FacetFieldProcessor extends FacetProcessor<FacetField> {
}
// overrides but with different signature!
private void addStats(SimpleOrderedMap<Object> target, int count, int slotNum) throws IOException {
private void addStats(SimpleOrderedMap<Object> target, long count, int slotNum) throws IOException {
target.add("count", count);
if (count > 0 || freq.processEmpty) {
for (SlotAcc acc : accs) {

View File

@ -57,8 +57,8 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
static final float LOAD_FACTOR = 0.7f;
long[] vals;
int[] counts; // maintain the counts here since we need them to tell if there was actually a value anyway
int[] oldToNewMapping;
long[] counts; // maintain the counts here since we need them to tell if there was actually a value anyway
long[] oldToNewMapping;
int cardinality;
int threshold;
@ -66,7 +66,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
/** sz must be a power of two */
LongCounts(int sz) {
vals = new long[sz];
counts = new int[sz];
counts = new long[sz];
threshold = (int) (sz * LOAD_FACTOR);
}
@ -95,7 +95,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
int h = hash(val);
for (int slot = h & (vals.length-1); ;slot = (slot + ((h>>7)|1)) & (vals.length-1)) {
int count = counts[slot];
long count = counts[slot];
if (count == 0) {
counts[slot] = 1;
vals[slot] = val;
@ -111,14 +111,14 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
protected void rehash() {
long[] oldVals = vals;
int[] oldCounts = counts; // after retrieving the count, this array is reused as a mapping to new array
long[] oldCounts = counts; // after retrieving the count, this array is reused as a mapping to new array
int newCapacity = vals.length << 1;
vals = new long[newCapacity];
counts = new int[newCapacity];
counts = new long[newCapacity];
threshold = (int) (newCapacity * LOAD_FACTOR);
for (int i=0; i<oldVals.length; i++) {
int count = oldCounts[i];
long count = oldCounts[i];
if (count == 0) {
oldCounts[i] = -1;
continue;
@ -287,12 +287,12 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
countAcc = new CountSlotAcc(fcontext) {
@Override
public void incrementCount(int slot, int count) {
public void incrementCount(int slot, long count) {
throw new UnsupportedOperationException();
}
@Override
public int getCount(int slot) {
public long getCount(int slot) {
return table.counts[slot];
}
@ -313,7 +313,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
@Override
public int compare(int slotA, int slotB) {
return Integer.compare( table.counts[slotA], table.counts[slotB] );
return Long.compare( table.counts[slotA], table.counts[slotB] );
}
@Override
@ -455,7 +455,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
}
final int finalNumSlots = numSlots;
final int[] mapping = table.oldToNewMapping;
final long[] mapping = table.oldToNewMapping;
SlotAcc.Resizer resizer = new SlotAcc.Resizer() {
@Override
@ -466,7 +466,7 @@ class FacetFieldProcessorByHashDV extends FacetFieldProcessor {
@Override
public int getNewSlot(int oldSlot) {
if (oldSlot < mapping.length) {
return mapping[oldSlot];
return (int) mapping[oldSlot];
}
if (oldSlot == oldAllBucketsSlot) {
return allBucketsSlot;

View File

@ -290,19 +290,19 @@ public abstract class FacetProcessor<FacetRequestT extends FacetRequest> {
return appliedFilters;
}
protected void processStats(SimpleOrderedMap<Object> bucket, Query bucketQ, DocSet docs, int docCount) throws IOException {
protected void processStats(SimpleOrderedMap<Object> bucket, Query bucketQ, DocSet docs, long docCount) throws IOException {
if (docCount == 0 && !freq.processEmpty || freq.getFacetStats().size() == 0) {
bucket.add("count", docCount);
return;
}
createAccs(docCount, 1);
int collected = collect(docs, 0, slotNum -> { return new SlotContext(bucketQ); });
long collected = collect(docs, 0, slotNum -> { return new SlotContext(bucketQ); });
countAcc.incrementCount(0, collected);
assert collected == docCount;
addStats(bucket, 0);
}
protected void createAccs(int docCount, int slotCount) throws IOException {
protected void createAccs(long docCount, int slotCount) throws IOException {
accMap = new LinkedHashMap<>();
// allow a custom count acc to be used
@ -332,8 +332,8 @@ public abstract class FacetProcessor<FacetRequestT extends FacetRequest> {
}
}
int collect(DocSet docs, int slot, IntFunction<SlotContext> slotContext) throws IOException {
int count = 0;
long collect(DocSet docs, int slot, IntFunction<SlotContext> slotContext) throws IOException {
long count = 0;
SolrIndexSearcher searcher = fcontext.searcher;
if (0 == docs.size()) {
@ -392,7 +392,7 @@ public abstract class FacetProcessor<FacetRequestT extends FacetRequest> {
}
void addStats(SimpleOrderedMap<Object> target, int slotNum) throws IOException {
int count = countAcc.getCount(slotNum);
long count = countAcc.getCount(slotNum);
target.add("count", count);
if (count > 0 || freq.processEmpty) {
for (SlotAcc acc : accs) {
@ -405,7 +405,7 @@ public abstract class FacetProcessor<FacetRequestT extends FacetRequest> {
boolean needDocSet = (skip==false && freq.getFacetStats().size() > 0) || freq.getSubFacets().size() > 0;
int count;
long count;
if (result != null) {
count = result.size();

View File

@ -578,7 +578,7 @@ class FacetRangeProcessor extends FacetProcessor<FacetRange> {
DocSet intersection = fcontext.searcher.getDocSet(rangeQ, fcontext.base);
filters[slot] = rangeQ;
intersections[slot] = intersection; // save for later // TODO: only save if number of slots is small enough?
int num = collect(intersection, slot, slotNum -> { return new SlotContext(rangeQ); });
long num = collect(intersection, slot, slotNum -> { return new SlotContext(rangeQ); });
countAcc.incrementCount(slot, num); // TODO: roll this into collect()
}

View File

@ -50,7 +50,7 @@ public class HLLAgg extends StrAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
SchemaField sf = fcontext.qcontext.searcher().getSchema().getField(getArg());
if (sf.multiValued() || sf.getType().multiValuedFieldCache()) {
if (sf.getType().isPointField()) {

View File

@ -46,7 +46,7 @@ public class MinMaxAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
SchemaField sf = null;

View File

@ -37,7 +37,7 @@ public class MissingAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {

View File

@ -49,7 +49,7 @@ public class PercentileAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {

View File

@ -122,7 +122,7 @@ public class RelatednessAgg extends AggValueSource {
}
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
// TODO: Ideally this is where we should check fgQ/bgQ for 'null' and apply defaults...
//
// we want to walk up the fcontext and inherit the queries from any ancestor SKGAgg

View File

@ -578,17 +578,17 @@ abstract class CountSlotAcc extends SlotAcc {
super(fcontext);
}
public abstract void incrementCount(int slot, int count);
public abstract void incrementCount(int slot, long count);
public abstract int getCount(int slot);
public abstract long getCount(int slot);
}
class CountSlotArrAcc extends CountSlotAcc {
int[] result;
long[] result;
public CountSlotArrAcc(FacetContext fcontext, int numSlots) {
super(fcontext);
result = new int[numSlots];
result = new long[numSlots];
}
@Override
@ -600,7 +600,7 @@ class CountSlotArrAcc extends CountSlotAcc {
@Override
public int compare(int slotA, int slotB) {
return Integer.compare(result[slotA], result[slotB]);
return Long.compare(result[slotA], result[slotB]);
}
@Override
@ -608,16 +608,18 @@ class CountSlotArrAcc extends CountSlotAcc {
return result[slotNum];
}
public void incrementCount(int slot, int count) {
@Override
public void incrementCount(int slot, long count) {
result[slot] += count;
}
public int getCount(int slot) {
@Override
public long getCount(int slot) {
return result[slot];
}
// internal and expert
int[] getCountArray() {
long[] getCountArray() {
return result;
}
@ -642,6 +644,7 @@ class SortSlotAcc extends SlotAcc {
// no-op
}
@Override
public int compare(int slotA, int slotB) {
return slotA - slotB;
}

View File

@ -32,7 +32,7 @@ public class StddevAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {

View File

@ -34,7 +34,7 @@ public class SumAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {

View File

@ -33,7 +33,7 @@ public class SumsqAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {

View File

@ -390,7 +390,7 @@ public class UnInvertedField extends DocTermOrds {
if (doNegative) {
for (int i=0; i<numTermsInField; i++) {
// counts[i] = maxTermCounts[i] - counts[i];
counts.incrementCount(i, maxTermCounts[i] - counts.getCount(i)*2);
counts.incrementCount(i, maxTermCounts[i] - (int) counts.getCount(i)*2);
}
}

View File

@ -42,7 +42,7 @@ public class UniqueAgg extends StrAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
SchemaField sf = fcontext.qcontext.searcher().getSchema().getField(getArg());
if (sf.multiValued() || sf.getType().multiValuedFieldCache()) {
if (sf.getType().isPointField()) {

View File

@ -79,7 +79,7 @@ public abstract class UniqueBlockAgg extends UniqueAgg {
}
@Override
public abstract SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException ;
public abstract SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException ;
@Override
public FacetMerger createFacetMerger(Object prototype) {

View File

@ -27,7 +27,7 @@ public class UniqueBlockFieldAgg extends UniqueBlockAgg {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
final String fieldName = getArg();
SchemaField sf = fcontext.qcontext.searcher().getSchema().getField(fieldName);
if (sf.multiValued() || sf.getType().multiValuedFieldCache()) {

View File

@ -65,7 +65,7 @@ public class UniqueBlockQueryAgg extends UniqueBlockAgg {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
return new UniqueBlockQuerySlotAcc(fcontext, query, numSlots);
}
}

View File

@ -31,7 +31,7 @@ public class VarianceAgg extends SimpleAggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
ValueSource vs = getArg();
if (vs instanceof FieldNameValueSource) {

View File

@ -518,16 +518,16 @@ public class CurrencyFieldTypeTest extends SolrTestCaseJ4 {
"{ xxx : { type:range, field:" + fieldName + ", " +
" start:'4.00"+suffix+"', gap:'1.00"+suffix+"', end:'11.00"+suffix+"', other:all } }")
,"count(//lst[@name='xxx']/arr[@name='buckets']/lst)=7"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='4.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='5.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='6.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='7.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='8.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='9.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='10.00,USD']]"
,"//lst[@name='xxx']/lst[@name='before' ]/int[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='after' ]/int[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/int[@name='count'][.='3']"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='4.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='5.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='6.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='7.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='8.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='9.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='10.00,USD']]"
,"//lst[@name='xxx']/lst[@name='before' ]/long[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='after' ]/long[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/long[@name='count'][.='3']"
);
}
@ -552,13 +552,13 @@ public class CurrencyFieldTypeTest extends SolrTestCaseJ4 {
"{ xxx : { type:range, mincount:1, field:" + fieldName +
", start:'0.00,USD', gap:'1.00,USD', end:'11.00,USD', other:all } }")
,"count(//lst[@name='xxx']/arr[@name='buckets']/lst)=4"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='3.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='4.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='7.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='10.00,USD']]"
,"//lst[@name='xxx']/lst[@name='before' ]/int[@name='count'][.='0']"
,"//lst[@name='xxx']/lst[@name='after' ]/int[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/int[@name='count'][.='4']"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='3.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='4.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='7.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='10.00,USD']]"
,"//lst[@name='xxx']/lst[@name='before' ]/long[@name='count'][.='0']"
,"//lst[@name='xxx']/lst[@name='after' ]/long[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/long[@name='count'][.='4']"
);
// NOTE: because of asymetric EUR exchange rate, these buckets are diff then the similar looking USD based request above
@ -587,16 +587,16 @@ public class CurrencyFieldTypeTest extends SolrTestCaseJ4 {
req("fl", "*,score", "q", "*:*", "rows", "0", "json.facet",
"{ xxx : { type:range, field:" + fieldName + ", start:'8.00,EUR', gap:'2.00,EUR', end:'22.00,EUR', other:all } }")
,"count(//lst[@name='xxx']/arr[@name='buckets']/lst)=7"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='8.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='10.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='12.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='14.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='16.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='18.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='20.00,EUR']]"
,"//lst[@name='xxx']/lst[@name='before' ]/int[@name='count'][.='2']"
,"//lst[@name='xxx']/lst[@name='after' ]/int[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/int[@name='count'][.='2']"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='8.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='10.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='12.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='14.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='16.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='18.00,EUR']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='20.00,EUR']]"
,"//lst[@name='xxx']/lst[@name='before' ]/long[@name='count'][.='2']"
,"//lst[@name='xxx']/lst[@name='after' ]/long[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/long[@name='count'][.='2']"
);
@ -627,16 +627,16 @@ public class CurrencyFieldTypeTest extends SolrTestCaseJ4 {
req("fl", "*,score", "q", "*:*", "rows", "0", "json.facet",
"{ xxx : { type:range, field:" + fieldName + ", start:'2.00,GBP', gap:'0.50,GBP', end:'5.50,GBP', other:all } }")
,"count(//lst[@name='xxx']/arr[@name='buckets']/lst)=7"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='2.00,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='2.50,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='3.00,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='3.50,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='4.00,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='4.50,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='5.00,GBP']]"
,"//lst[@name='xxx']/lst[@name='before' ]/int[@name='count'][.='0']"
,"//lst[@name='xxx']/lst[@name='after' ]/int[@name='count'][.='2']"
,"//lst[@name='xxx']/lst[@name='between']/int[@name='count'][.='3']"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='2.00,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='2.50,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='3.00,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='3.50,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='4.00,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='4.50,GBP']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='5.00,GBP']]"
,"//lst[@name='xxx']/lst[@name='before' ]/long[@name='count'][.='0']"
,"//lst[@name='xxx']/lst[@name='after' ]/long[@name='count'][.='2']"
,"//lst[@name='xxx']/lst[@name='between']/long[@name='count'][.='3']"
);
assertQ("Ensure that we can set a gap in a currency other than the start and end currencies (facet.range)",
@ -663,17 +663,17 @@ public class CurrencyFieldTypeTest extends SolrTestCaseJ4 {
req("fl", "*,score", "q", "*:*", "rows", "0", "json.facet",
"{ xxx : { type:range, field:" + fieldName + ", start:'4.00,USD', gap:'0.50,GBP', end:'11.00,USD', other:all } }")
,"count(//lst[@name='xxx']/arr[@name='buckets']/lst)=7"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='4.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='5.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='6.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='7.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='8.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='0']][str[@name='val'][.='9.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[int[@name='count'][.='1']][str[@name='val'][.='10.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='4.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='5.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='6.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='7.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='8.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='0']][str[@name='val'][.='9.00,USD']]"
,"//lst[@name='xxx']/arr[@name='buckets']/lst[long[@name='count'][.='1']][str[@name='val'][.='10.00,USD']]"
,"//lst[@name='xxx']/lst[@name='before' ]/int[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='after' ]/int[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/int[@name='count'][.='3']"
,"//lst[@name='xxx']/lst[@name='before' ]/long[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='after' ]/long[@name='count'][.='1']"
,"//lst[@name='xxx']/lst[@name='between']/long[@name='count'][.='3']"
);
for (SolrParams facet : Arrays.asList(params("facet", "true",

View File

@ -193,9 +193,9 @@ public class TestSortableTextField extends SolrTestCaseJ4 {
assertQ(req("q", search + ":cow", "rows", "0",
"json.facet", "{x:{ type: terms, field:'" + facet + "', mincount:0 }}")
, "//*[@numFound='3']"
, jpre + "lst[str[@name='val'][.='how now brown cow ?']][int[@name='count'][.=2]]"
, jpre + "lst[str[@name='val'][.='holy cow !']][int[@name='count'][.=1]]"
, jpre + "lst[str[@name='val'][.='dog and cat']][int[@name='count'][.=0]]"
, jpre + "lst[str[@name='val'][.='how now brown cow ?']][long[@name='count'][.=2]]"
, jpre + "lst[str[@name='val'][.='holy cow !']][long[@name='count'][.=1]]"
, jpre + "lst[str[@name='val'][.='dog and cat']][long[@name='count'][.=0]]"
);
}

View File

@ -50,7 +50,7 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
private static String FIELD = null; // randomized
private static final List<String> STR_VALS = Arrays.asList("x0", "x1", "x2");
// NOTE: in our test conversions EUR uses an asynetric echange rate
// NOTE: in our test conversions EUR uses an asynetric exchange rate
// these are the equivalent values relative to: USD EUR GBP
private static final List<String> VALUES = Arrays.asList("10.00,USD", // 10.00,USD 25.00,EUR 5.00,GBP
"15.00,EUR", // 7.50,USD 15.00,EUR 7.50,GBP
@ -176,9 +176,9 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
final NamedList<Object> foo = ((NamedList<NamedList<Object>>)rsp.getResponse().get("facets")).get("foo");
assertEqualsHACK("before", 3L, ((NamedList)foo.get("before")).get("count"));
assertEqualsHACK("after", 3L, ((NamedList)foo.get("after")).get("count"));
assertEqualsHACK("between", 9L, ((NamedList)foo.get("between")).get("count"));
assertEquals("before", 3L, ((NamedList)foo.get("before")).get("count"));
assertEquals("after", 3L, ((NamedList)foo.get("after")).get("count"));
assertEquals("between", 9L, ((NamedList)foo.get("between")).get("count"));
final List<NamedList> buckets = (List<NamedList>) foo.get("buckets");
@ -187,14 +187,14 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
for (int i = 0; i < 3; i++) {
NamedList bucket = buckets.get(i);
assertEquals((4 + (3 * i)) + ".00,USD", bucket.get("val"));
assertEqualsHACK("bucket #" + i, 3L, bucket.get("count"));
assertEquals("bucket #" + i, 3L, bucket.get("count"));
}
} else {
assertEquals(7, buckets.size());
for (int i = 0; i < 7; i++) {
NamedList bucket = buckets.get(i);
assertEquals((4 + i) + ".00,USD", bucket.get("val"));
assertEqualsHACK("bucket #" + i, (i == 0 || i == 3 || i == 6) ? 3L : 0L, bucket.get("count"));
assertEquals("bucket #" + i, (i == 0 || i == 3 || i == 6) ? 3L : 0L, bucket.get("count"));
}
}
} catch (AssertionError|RuntimeException ae) {
@ -268,9 +268,9 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
final NamedList<Object> foo = ((NamedList<NamedList<Object>>)rsp.getResponse().get("facets")).get("foo");
assertEqualsHACK("before", 6L, ((NamedList)foo.get("before")).get("count"));
assertEqualsHACK("after", 3L, ((NamedList)foo.get("after")).get("count"));
assertEqualsHACK("between", 6L, ((NamedList)foo.get("between")).get("count"));
assertEquals("before", 6L, ((NamedList)foo.get("before")).get("count"));
assertEquals("after", 3L, ((NamedList)foo.get("after")).get("count"));
assertEquals("between", 6L, ((NamedList)foo.get("between")).get("count"));
final List<NamedList> buckets = (List<NamedList>) foo.get("buckets");
@ -279,14 +279,14 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
for (int i = 0; i < 2; i++) {
NamedList bucket = buckets.get(i);
assertEquals((12 + (i * 2)) + ".00,EUR", bucket.get("val"));
assertEqualsHACK("bucket #" + i, 3L, bucket.get("count"));
assertEquals("bucket #" + i, 3L, bucket.get("count"));
}
} else {
assertEquals(7, buckets.size());
for (int i = 0; i < 7; i++) {
NamedList bucket = buckets.get(i);
assertEquals((8 + (i * 2)) + ".00,EUR", bucket.get("val"));
assertEqualsHACK("bucket #" + i, (i == 2 || i == 3) ? 3L : 0L, bucket.get("count"));
assertEquals("bucket #" + i, (i == 2 || i == 3) ? 3L : 0L, bucket.get("count"));
}
}
} catch (AssertionError|RuntimeException ae) {
@ -365,9 +365,9 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
// sanity check our high level expectations...
assertEquals("bar num buckets", 2, bar_buckets.size());
assertEqualsHACK("before count", 0L, before.get("count"));
assertEqualsHACK("between count", 8L, between.get("count"));
assertEqualsHACK("after count", 2L, after.get("count"));
assertEquals("before count", 0L, before.get("count"));
assertEquals("between count", 8L, between.get("count"));
assertEquals("after count", 2L, after.get("count"));
// drill into the various buckets...
@ -378,15 +378,15 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
for (int i = 0; i < 2; i++) {
final NamedList<Object> bucket = bar_buckets.get(i);
assertEquals((i * 10) + ".00,EUR", bucket.get("val"));
assertEqualsHACK("bucket #" + i, 4L, bucket.get("count"));
assertEquals("bucket #" + i, 4L, bucket.get("count"));
final List<NamedList<Object>> foo_buckets = ((NamedList<List<NamedList<Object>>>)bucket.get("foo")).get("buckets");
assertEquals("bucket #" + i + " foo num buckets", 2, foo_buckets.size());
assertEquals("bucket #" + i + " foo top term", (0==i ? "x2" : "x0"), foo_buckets.get(0).get("val"));
assertEqualsHACK("bucket #" + i + " foo top count", 2, foo_buckets.get(0).get("count"));
assertEquals("bucket #" + i + " foo top count", 2L, foo_buckets.get(0).get("count"));
// NOTE: we can't make any assertions about the 2nd val..
// our limit + randomized sharding could result in either remaining term being picked.
// but for eiter term, the count should be exactly the same...
assertEqualsHACK("bucket #" + i + " foo 2nd count", 1, foo_buckets.get(1).get("count"));
// but for either term, the count should be exactly the same...
assertEquals("bucket #" + i + " foo 2nd count", 1L, foo_buckets.get(1).get("count"));
}
{ // between...
@ -394,9 +394,9 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
assertEquals("between num buckets", 2, buckets.size());
// the counts should both be 3, and the term order should break the tie...
assertEquals("between bucket top", "x0", buckets.get(0).get("val"));
assertEqualsHACK("between bucket top count", 3L, buckets.get(0).get("count"));
assertEquals("between bucket top count", 3L, buckets.get(0).get("count"));
assertEquals("between bucket 2nd", "x2", buckets.get(1).get("val"));
assertEqualsHACK("between bucket 2nd count", 3L, buckets.get(1).get("count"));
assertEquals("between bucket 2nd count", 3L, buckets.get(1).get("count"));
}
{ // after...
@ -404,9 +404,9 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
assertEquals("after num buckets", 2, buckets.size());
// the counts should both be 1, and the term order should break the tie...
assertEquals("after bucket top", "x1", buckets.get(0).get("val"));
assertEqualsHACK("after bucket top count", 1L, buckets.get(0).get("count"));
assertEquals("after bucket top count", 1L, buckets.get(0).get("count"));
assertEquals("after bucket 2nd", "x2", buckets.get(1).get("val"));
assertEqualsHACK("after bucket 2nd count", 1L, buckets.get(1).get("count"));
assertEquals("after bucket 2nd count", 1L, buckets.get(1).get("count"));
}
} catch (AssertionError|RuntimeException ae) {
@ -449,15 +449,15 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
final List<NamedList<Object>> foo_buckets = (List<NamedList<Object>>) foo.get("buckets");
assertEquals(1, foo_buckets.size());
assertEquals("x2", foo_buckets.get(0).get("val"));
assertEqualsHACK("foo bucket count", 5L, foo_buckets.get(0).get("count"));
assertEquals("foo bucket count", 5L, foo_buckets.get(0).get("count"));
final NamedList<Object> bar = (NamedList<Object>)foo_buckets.get(0).get("bar");
// these are the 'x2' specific counts, based on our fq...
assertEqualsHACK("before", 2L, ((NamedList)bar.get("before")).get("count"));
assertEqualsHACK("after", 1L, ((NamedList)bar.get("after")).get("count"));
assertEqualsHACK("between", 2L, ((NamedList)bar.get("between")).get("count"));
assertEquals("before", 2L, ((NamedList)bar.get("before")).get("count"));
assertEquals("after", 1L, ((NamedList)bar.get("after")).get("count"));
assertEquals("between", 2L, ((NamedList)bar.get("between")).get("count"));
final List<NamedList> buckets = (List<NamedList>) bar.get("buckets");
assertEquals(7, buckets.size());
@ -465,7 +465,7 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
NamedList bucket = buckets.get(i);
assertEquals((8 + (i * 2)) + ".00,EUR", bucket.get("val"));
// 12,EUR & 15,EUR are the 2 values that align with x2 docs
assertEqualsHACK("bucket #" + i, (i == 2 || i == 3) ? 1L : 0L, bucket.get("count"));
assertEquals("bucket #" + i, (i == 2 || i == 3) ? 1L : 0L, bucket.get("count"));
}
} catch (AssertionError|RuntimeException ae) {
throw new AssertionError(solrQuery.toString() + " -> " + rsp.toString() + " ===> " + ae.getMessage(), ae);
@ -473,14 +473,4 @@ public class CurrencyRangeFacetCloudTest extends SolrCloudTestCase {
}
}
/**
* HACK to work around SOLR-11775.
* Asserts that the 'actual' argument is a (non-null) Number, then compares it's 'longValue' to the 'expected' argument
*/
private static void assertEqualsHACK(String msg, long expected, Object actual) {
assertNotNull(msg, actual);
assertTrue(msg + " ... NOT A NUMBER: " + actual.getClass(), Number.class.isInstance(actual));
assertEquals(msg, expected, ((Number)actual).longValue());
}
}

View File

@ -68,7 +68,7 @@ class DebugAgg extends AggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) throws IOException {
return new Acc(fcontext, numDocs, numSlots, inner.createSlotAcc(fcontext, numDocs, numSlots));
}
@ -91,10 +91,10 @@ class DebugAgg extends AggValueSource {
public static Acc last;
public SlotAcc sub;
public int numDocs;
public long numDocs;
public int numSlots;
public Acc(FacetContext fcontext, int numDocs, int numSlots, SlotAcc sub) {
public Acc(FacetContext fcontext, long numDocs, int numSlots, SlotAcc sub) {
super(fcontext);
this.last = this;
this.numDocs = numDocs;
@ -173,7 +173,7 @@ class DebugAgg extends AggValueSource {
}
@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) {
public SlotAcc createSlotAcc(FacetContext fcontext, long numDocs, int numSlots) {
return new NumShardsAcc(fcontext, numDocs, numSlots);
}
@ -188,7 +188,7 @@ class DebugAgg extends AggValueSource {
}
public static class NumShardsAcc extends SlotAcc {
public NumShardsAcc(FacetContext fcontext, int numDocs, int numSlots) {
public NumShardsAcc(FacetContext fcontext, long numDocs, int numSlots) {
super(fcontext);
}

View File

@ -147,7 +147,7 @@ public class DistributedFacetSimpleRefinementLongTailTest extends BaseDistribute
for (int j = 0; j < 5; j++) {
NamedList bucket = shardFooBuckets[i].get(j);
assertEquals(bucket.toString(), "aaa"+j, bucket.get("val"));
assertEquals(bucket.toString(), 100, bucket.get("count"));
assertEquals(bucket.toString(), 100L, bucket.get("count"));
}
}
// top 6-10 same on shard0 & shard1
@ -155,19 +155,19 @@ public class DistributedFacetSimpleRefinementLongTailTest extends BaseDistribute
for (int j = 5; j < 10; j++) {
NamedList bucket = shardFooBuckets[i].get(j);
assertTrue(bucket.toString(), bucket.get("val").toString().startsWith("bbb"));
assertEquals(bucket.toString(), 50, bucket.get("count"));
assertEquals(bucket.toString(), 50L, bucket.get("count"));
}
}
// 6-10 on shard2
assertEquals("junkA", shardFooBuckets[2].get(5).get("val"));
assertEquals(50, shardFooBuckets[2].get(5).get("count"));
assertEquals(50L, shardFooBuckets[2].get(5).get("count"));
assertEquals("tail", shardFooBuckets[2].get(6).get("val"));
assertEquals(45, shardFooBuckets[2].get(6).get("count"));
assertEquals(45L, shardFooBuckets[2].get(6).get("count"));
for (int j = 7; j < 10; j++) {
NamedList bucket = shardFooBuckets[2].get(j);
assertTrue(bucket.toString(), bucket.get("val").toString().startsWith("ZZZ"));
assertEquals(bucket.toString(), 1, bucket.get("count"));
assertEquals(bucket.toString(), 1L, bucket.get("count"));
}
// check 'bar' sub buckets on "tail" from shard2
@ -176,11 +176,11 @@ public class DistributedFacetSimpleRefinementLongTailTest extends BaseDistribute
for (int j = 0; j < 5; j++) {
NamedList bucket = bar_buckets.get(j);
assertTrue(bucket.toString(), bucket.get("val").toString().startsWith("junkB"));
assertEquals(bucket.toString(), 8, bucket.get("count"));
assertEquals(bucket.toString(), 8L, bucket.get("count"));
}
NamedList bucket = bar_buckets.get(5);
assertEquals("tailB", bucket.get("val"));
assertEquals(5, bucket.get("count"));
assertEquals(5L, bucket.get("count"));
}
}

View File

@ -741,7 +741,7 @@ public class RangeFacetCloudTest extends SolrCloudTestCase {
toMerge.add(TERM_MODEL[i]);
}
assertEqualsHACK("count", expectedCount, bucket.get("count"));
assertEquals("count", expectedCount, bucket.get("count"));
// merge the maps of our range values by summing the (int) values on key collisions
final Map<String,Long> expectedTermCounts = toMerge.stream()
@ -766,7 +766,7 @@ public class RangeFacetCloudTest extends SolrCloudTestCase {
assertNotNull("subfacet bucket with null term: " + subBucket, term);
final Long expectedTermCount = expectedTermCounts.get(term.toString());
assertNotNull("unexpected subfacet bucket: " + subBucket, expectedTermCount);
assertEqualsHACK("subfacet count for term: " + term, expectedTermCount, subBucket.get("count"));
assertEquals("subfacet count for term: " + term, expectedTermCount, subBucket.get("count"));
}
}
@ -910,14 +910,4 @@ public class RangeFacetCloudTest extends SolrCloudTestCase {
return ", other:" + val;
}
/**
* HACK to work around SOLR-11775.
* Asserts that the 'actual' argument is a (non-null) Number, then compares it's 'longValue' to the 'expected' argument
*/
private static void assertEqualsHACK(String msg, long expected, Object actual) {
assertNotNull(msg, actual);
assertTrue(msg + " ... NOT A NUMBER: " + actual.getClass(), Number.class.isInstance(actual));
assertEquals(msg, expected, ((Number)actual).longValue());
}
}

View File

@ -3283,6 +3283,64 @@ public class TestJsonFacets extends SolrTestCaseHS {
}
@Test
public void testFacetValueTypes() throws Exception {
doFacetValueTypeValidation(Client.localClient());
}
@Test
public void testFacetValueTypesDistrib() throws Exception {
initServers();
Client client = servers.getClient(random().nextInt());
client.queryDefaults().set( "shards", servers.getShards(), "debugQuery", Boolean.toString(random().nextBoolean()) );
doFacetValueTypeValidation(client);
}
private void doFacetValueTypeValidation(Client client) throws Exception {
indexSimple(client);
client.testXQ(params("q", "*:*", "rows", "0",
"json.facet", "{cat_s:{type:terms,field:cat_s,mincount:0,missing:true,allBuckets:true,numBuckets:true,limit:1}}"),
"/response/lst[@name='facets']/long[@name='count'][.=6]", // count
"/response/lst[@name='facets']/lst[@name='cat_s']/long[@name='numBuckets'][.=2]", // total no of buckets
"*[count(/response/lst[@name='facets']/lst[@name='cat_s']/arr[@name='buckets']/lst)=1]", // no of entries
"/response/lst[@name='facets']/lst[@name='cat_s']/lst[@name='allBuckets']/long[@name='count'][.=5]", // allBuckets
"/response/lst[@name='facets']/lst[@name='cat_s']/lst[@name='missing']/long[@name='count'][.=1]", // missing
"/response/lst[@name='facets']/lst[@name='cat_s']/arr[@name='buckets']/lst[1]/str[@name='val'][.='B']", // facet value
"/response/lst[@name='facets']/lst[@name='cat_s']/arr[@name='buckets']/lst[1]/long[@name='count'][.='3']" // facet count
);
// aggregations types for string
client.testXQ(params("q", "*:*", "rows", "0",
"json.facet", "{unique:'unique(cat_s)',hll:'hll(cat_s)',vals:'countvals(cat_s)',missing:'missing(cat_s)'}"),
"/response/lst[@name='facets']/long[@name='count'][.=6]", // count
"/response/lst[@name='facets']/long[@name='unique'][.=2]", // unique
"/response/lst[@name='facets']/long[@name='hll'][.=2]", // hll
"/response/lst[@name='facets']/long[@name='vals'][.=5]", // values
"/response/lst[@name='facets']/long[@name='missing'][.=1]" // missing
);
// aggregations types for number
client.testXQ(params("q", "*:*", "rows", "0",
"json.facet", "{unique:'unique(num_i)',hll:'hll(num_i)',vals:'countvals(num_i)',missing:'missing(num_i)'}"),
"/response/lst[@name='facets']/long[@name='count'][.=6]", // count
"/response/lst[@name='facets']/long[@name='unique'][.=4]", // unique
"/response/lst[@name='facets']/long[@name='hll'][.=4]", // hll
"/response/lst[@name='facets']/long[@name='vals'][.=5]", // values
"/response/lst[@name='facets']/long[@name='missing'][.=1]" // missing
);
// aggregations types for multi-valued number
client.testXQ(params("q", "*:*", "rows", "0",
"json.facet", "{unique:'unique(num_is)',hll:'hll(num_is)',vals:'countvals(num_is)',missing:'missing(num_is)'}"),
"/response/lst[@name='facets']/long[@name='count'][.=6]", // count
"/response/lst[@name='facets']/long[@name='unique'][.=7]", // unique
"/response/lst[@name='facets']/long[@name='hll'][.=7]", // hll
"/response/lst[@name='facets']/long[@name='vals'][.=9]", // values
"/response/lst[@name='facets']/long[@name='missing'][.=1]" // missing
);
}
public void XtestPercentiles() {
AVLTreeDigest catA = new AVLTreeDigest(100);
catA.add(4);

View File

@ -394,4 +394,42 @@ public class TestJsonRangeFacets extends SolrTestCaseHS {
"facets=={count:6, price:{buckets:[{val:\"[*,*)\",count:5}]}}");
}
@Test
public void testFacetValueTypes() throws Exception {
doFacetValueTypeValidation(Client.localClient());
}
@Test
public void testFacetValueTypeDistrib() throws Exception {
initServers();
Client client = servers.getClient(random().nextInt());
client.queryDefaults().set( "shards", servers.getShards(), "debugQuery", Boolean.toString(random().nextBoolean()) );
doFacetValueTypeValidation(client);
}
private void doFacetValueTypeValidation(Client client) throws Exception {
indexSimple(client);
// range faceting with start, end, and gap
client.testXQ(params("q", "*:*", "rows", "0",
"json.facet", "{num:{type: range, field:num_i,start:0,gap:2,end:10,mincount:1,other:all}}"),
"/response/lst[@name='facets']/long[@name='count'][.=6]", // count
"/response/lst[@name='facets']/lst[@name='num']/arr[@name='buckets']/lst[1]/int[@name='val'][.=2]", // value
"/response/lst[@name='facets']/lst[@name='num']/arr[@name='buckets']/lst[1]/long[@name='count'][.=2]", // count
"*[count(/response/lst[@name='facets']/lst[@name='num']/arr[@name='buckets']/lst)=2]", // no of entries
"/response/lst[@name='facets']/lst[@name='num']/lst[@name='before']/long[@name='count'][.=2]", // before
"/response/lst[@name='facets']/lst[@name='num']/lst[@name='after']/long[@name='count'][.=0]", // after
"/response/lst[@name='facets']/lst[@name='num']/lst[@name='between']/long[@name='count'][.=3]" // between
);
// range faceting with ranges specified
client.testXQ(params("q", "*:*", "rows", "0",
"json.facet", "{num:{type: range, field:num_i,ranges:[{from:0, to:4},{from:-4,to:2}],mincount:1}}"),
"/response/lst[@name='facets']/long[@name='count'][.=6]", // count
"/response/lst[@name='facets']/lst[@name='num']/arr[@name='buckets']/lst[1]/str[@name='val'][.='[0,4)']", // value
"/response/lst[@name='facets']/lst[@name='num']/arr[@name='buckets']/lst[1]/long[@name='count'][.=2]", // count
"*[count(/response/lst[@name='facets']/lst[@name='num']/arr[@name='buckets']/lst)=1]" // no of entries
);
}
}

View File

@ -104,6 +104,8 @@ _(raw; not yet edited)_
* SOLR-12720: To change the auto add replica wait period modify the `waitFor` attribute of the `.auto_add_replicas` trigger.
(marcussorealheis, shalin)
* SOLR-11775: Return long value for facet count in Json Facet module irrespective of number of shards (hossman, Munendra S N)
=== Upgrade Prerequisites in Solr 9
=== Rolling Upgrades with Solr 9

View File

@ -16,6 +16,7 @@
*/
package org.apache.solr;
import javax.xml.xpath.XPathExpressionException;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
@ -45,6 +46,7 @@ import org.apache.solr.client.solrj.impl.NoOpResponseParser;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
@ -54,6 +56,7 @@ import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.servlet.DirectSolrConnection;
import org.apache.solr.util.TestHarness;
import org.noggit.JSONUtil;
import org.noggit.ObjectBuilder;
import org.slf4j.Logger;
@ -145,6 +148,31 @@ public class SolrTestCaseHS extends SolrTestCaseJ4 {
matchJSON(resp, tests);
}
/**
* Pass "null" for the client to query to the local server.
* Fetches response in xml format and matches with the given set of xpaths
*/
public static void assertQ(SolrClient client, SolrParams args, String... tests) throws Exception {
String resp;
resp = getQueryResponse(client, "xml", args);
try {
String results = TestHarness.validateXPath(resp, tests);
if (null != results) {
String msg = "REQUEST FAILED: xpath=" + results
+ "\n\txml response was: " + resp
+ "\n\tparams were:" + args.toQueryString();
log.error(msg);
throw new RuntimeException(msg);
}
} catch (XPathExpressionException e1) {
throw new RuntimeException("XPath is invalid", e1);
} catch (Exception e2) {
SolrException.log(log,"REQUEST FAILED for params: " + args.toQueryString(), e2);
throw new RuntimeException("Exception during query", e2);
}
}
public static void matchJSON(String response, String... tests) throws Exception {
boolean failed = false;
@ -256,6 +284,10 @@ public class SolrTestCaseHS extends SolrTestCaseJ4 {
public void assertJQ(SolrClient client, SolrParams args, String... tests) throws Exception {
SolrTestCaseHS.assertJQ(client, args, tests);
}
public void assertQ(SolrClient client, SolrParams args, String... tests) throws Exception {
SolrTestCaseHS.assertQ(client, args, tests);
}
}
public static Client localClient = new Client(null, 1);
@ -299,6 +331,19 @@ public class SolrTestCaseHS extends SolrTestCaseJ4 {
tester.assertJQ(client, args, tests);
}
/**
* tests are validated against xml response
*/
public void testXQ(SolrParams args, String... tests) throws Exception {
if (queryDefaults != null) {
ModifiableSolrParams newParams = params(queryDefaults);
newParams.add(args);
args = newParams;
}
SolrClient client = provider==null ? null : provider.client(null, args);
tester.assertQ(client, args, tests);
}
public Long add(SolrInputDocument sdoc, ModifiableSolrParams params) throws Exception {
SolrClient client = provider==null ? null : provider.client(sdoc, params);
return SolrTestCaseHS.add(client, sdoc, params);