You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by da...@apache.org on 2020/04/02 08:04:15 UTC
[lucene-solr] 01/01: SOLR-14365: CollapsingQParser - Avoiding
always allocate int[] and float[] with size equals to number of unique
values (WIP)
This is an automated email from the ASF dual-hosted git repository.
datcm pushed a commit to branch jira/SOLR-14365
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
commit 0d82a9f5cdac67c9de92c979e016c1c6b1f8dcf4
Author: Cao Manh Dat <da...@apache.org>
AuthorDate: Thu Apr 2 15:03:44 2020 +0700
SOLR-14365: CollapsingQParser - Avoiding always allocate int[] and float[] with size equals to number of unique values (WIP)
---
.../solr/search/CollapsingQParserPlugin.java | 335 ++++++++++-----------
.../apache/solr/util/numeric/FloatConsumer.java | 23 ++
.../solr/util/numeric/IntFloatArrayBasedMap.java | 69 +++++
.../apache/solr/util/numeric/IntFloatHashMap.java | 44 +++
.../org/apache/solr/util/numeric/IntFloatMap.java | 26 ++
.../solr/util/numeric/IntIntArrayBasedMap.java | 81 +++++
.../apache/solr/util/numeric/IntIntHashMap.java | 60 ++++
.../org/apache/solr/util/numeric/IntIntMap.java | 29 ++
.../solr/util/numeric/IntLongArrayBasedMap.java | 76 +++++
.../apache/solr/util/numeric/IntLongHashMap.java | 51 ++++
.../org/apache/solr/util/numeric/IntLongMap.java | 28 ++
.../solr/util/numeric/PrimitiveMapFactory.java | 62 ++++
.../org/apache/solr/util/numeric/package-info.java | 23 ++
13 files changed, 730 insertions(+), 177 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
index 690f806..c6ea397 100644
--- a/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
+++ b/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
@@ -17,6 +17,7 @@
package org.apache.solr.search;
import java.io.IOException;
+import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -33,6 +34,7 @@ import com.carrotsearch.hppc.IntLongHashMap;
import com.carrotsearch.hppc.cursors.IntIntCursor;
import com.carrotsearch.hppc.cursors.IntLongCursor;
import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.spi.LoggerRegistry;
import org.apache.lucene.codecs.DocValuesProducer;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.DocValuesType;
@@ -78,6 +80,12 @@ import org.apache.solr.schema.NumberType;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.schema.StrField;
import org.apache.solr.uninverting.UninvertingReader;
+import org.apache.solr.util.numeric.IntFloatMap;
+import org.apache.solr.util.numeric.IntIntMap;
+import org.apache.solr.util.numeric.IntLongMap;
+import org.apache.solr.util.numeric.PrimitiveMapFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static org.apache.solr.common.params.CommonParams.SORT;
@@ -118,6 +126,7 @@ import static org.apache.solr.common.params.CommonParams.SORT;
public class CollapsingQParserPlugin extends QParserPlugin {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static final String NAME = "collapse";
public static final String NULL_COLLAPSE = "collapse";
public static final String NULL_IGNORE = "ignore";
@@ -510,8 +519,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private SortedDocValues segmentValues;
private LongValues segmentOrdinalMap;
private MultiDocValues.MultiSortedDocValues multiSortedDocValues;
- private int[] ords;
- private float[] scores;
+ private IntIntMap ords;
+ private IntFloatMap scores;
private int maxDoc;
private int nullPolicy;
private float nullScore = -Float.MAX_VALUE;
@@ -524,6 +533,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public OrdScoreCollector(int maxDoc,
int segments,
+ PrimitiveMapFactory mapFactory,
DocValuesProducer collapseValuesProducer,
int nullPolicy,
IntIntHashMap boostDocsMap,
@@ -544,10 +554,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.multiSortedDocValues = (MultiDocValues.MultiSortedDocValues)collapseValues;
this.ordinalMap = multiSortedDocValues.mapping;
}
- this.ords = new int[valueCount];
- Arrays.fill(this.ords, -1);
- this.scores = new float[valueCount];
- Arrays.fill(this.scores, -Float.MAX_VALUE);
+ this.ords = mapFactory.newIntIntMap(valueCount, -1);
+ this.scores = mapFactory.newIntFloatMap(valueCount, -Float.MAX_VALUE);
this.nullPolicy = nullPolicy;
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
@@ -613,9 +621,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
if(ord > -1) {
float score = scorer.score();
- if(score > scores[ord]) {
- ords[ord] = globalDoc;
- scores[ord] = score;
+ if(score > scores.get(ord)) {
+ ords.set(ord, globalDoc);
+ scores.set(ord, score);
}
} else if(nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
float score = scorer.score();
@@ -646,7 +654,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int ord = this.boostOrds.get(i);
if(ord > -1) {
//Remove any group heads that are in the same groups as boosted documents.
- ords[ord] = -1;
+ ords.remove(ord);
}
//Add the boosted docs to the collapsedSet
this.collapsedSet.set(boostDocs.get(i));
@@ -655,12 +663,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
//Build the sorted DocSet of group heads.
- for(int i=0; i<ords.length; i++) {
- int doc = ords[i];
- if(doc > -1) {
- collapsedSet.set(doc);
- }
- }
+ ords.forEachValue(doc -> collapsedSet.set(doc));
int currentContext = 0;
int currentDocBase = 0;
@@ -715,7 +718,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
if(ord > -1) {
- dummy.score = scores[ord];
+ dummy.score = scores.get(ord);
} else if(boosts && mergeBoost.boost(docId)) {
//Ignore so it doesn't mess up the null scoring.
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -957,6 +960,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public OrdFieldValueCollector(int maxDoc,
int segments,
+ PrimitiveMapFactory mapFactory,
DocValuesProducer collapseValuesProducer,
int nullPolicy,
GroupHeadSelector groupHeadSelector,
@@ -987,9 +991,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.needsScores4Collapsing = needsScores4Collapsing;
this.needsScores = needsScores;
if (null != sortSpec) {
- this.collapseStrategy = new OrdSortSpecStrategy(maxDoc, nullPolicy, new int[valueCount], groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocs, sortSpec, searcher, collapseValues);
+ this.collapseStrategy = new OrdSortSpecStrategy(maxDoc, nullPolicy, valueCount, mapFactory, groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocs, sortSpec, searcher, collapseValues);
} else if (funcQuery != null) {
- this.collapseStrategy = new OrdValueSourceStrategy(maxDoc, nullPolicy, new int[valueCount], groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocs, funcQuery, searcher, collapseValues);
+ this.collapseStrategy = new OrdValueSourceStrategy(maxDoc, nullPolicy, valueCount, mapFactory, groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocs, funcQuery, searcher, collapseValues);
} else {
NumberType numType = fieldType.getNumberType();
if (null == numType) {
@@ -997,15 +1001,15 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
switch (numType) {
case INTEGER: {
- this.collapseStrategy = new OrdIntStrategy(maxDoc, nullPolicy, new int[valueCount], groupHeadSelector, this.needsScores, boostDocs, collapseValues);
+ this.collapseStrategy = new OrdIntStrategy(maxDoc, nullPolicy, valueCount, mapFactory, groupHeadSelector, this.needsScores, boostDocs, collapseValues);
break;
}
case FLOAT: {
- this.collapseStrategy = new OrdFloatStrategy(maxDoc, nullPolicy, new int[valueCount], groupHeadSelector, this.needsScores, boostDocs, collapseValues);
+ this.collapseStrategy = new OrdFloatStrategy(maxDoc, nullPolicy, valueCount, mapFactory, groupHeadSelector, this.needsScores, boostDocs, collapseValues);
break;
}
case LONG: {
- this.collapseStrategy = new OrdLongStrategy(maxDoc, nullPolicy, new int[valueCount], groupHeadSelector, this.needsScores, boostDocs, collapseValues);
+ this.collapseStrategy = new OrdLongStrategy(maxDoc, nullPolicy, valueCount, mapFactory, groupHeadSelector, this.needsScores, boostDocs, collapseValues);
break;
}
default: {
@@ -1075,7 +1079,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
DocIdSetIterator it = new BitSetIterator(collapseStrategy.getCollapsedSet(), 0); // cost is not useful here
int globalDoc = -1;
int nullScoreIndex = 0;
- float[] scores = collapseStrategy.getScores();
+ IntFloatMap scores = collapseStrategy.getScores();
FloatArrayList nullScores = collapseStrategy.getNullScores();
float nullScore = collapseStrategy.getNullScore();
@@ -1112,7 +1116,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
if(ord > -1) {
- dummy.score = scores[ord];
+ dummy.score = scores.get(ord);
} else if (mergeBoost != null && mergeBoost.boost(globalDoc)) {
//It's an elevated doc so no score is needed
dummy.score = 0F;
@@ -1151,6 +1155,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public IntFieldValueCollector(int maxDoc,
int size,
+ PrimitiveMapFactory mapFactory,
int segments,
int nullValue,
int nullPolicy,
@@ -1178,19 +1183,19 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.needsScores4Collapsing = needsScores4Collapsing;
this.needsScores = needsScores;
if (null != sortSpec) {
- this.collapseStrategy = new IntSortSpecStrategy(maxDoc, size, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocsMap, sortSpec, searcher);
+ this.collapseStrategy = new IntSortSpecStrategy(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocsMap, sortSpec, searcher);
} else if (funcQuery != null) {
- this.collapseStrategy = new IntValueSourceStrategy(maxDoc, size, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocsMap, funcQuery, searcher);
+ this.collapseStrategy = new IntValueSourceStrategy(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores4Collapsing, this.needsScores, boostDocsMap, funcQuery, searcher);
} else {
NumberType numType = fieldType.getNumberType();
assert null != numType; // shouldn't make it here for non-numeric types
switch (numType) {
case INTEGER: {
- this.collapseStrategy = new IntIntStrategy(maxDoc, size, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores, boostDocsMap);
+ this.collapseStrategy = new IntIntStrategy(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores, boostDocsMap);
break;
}
case FLOAT: {
- this.collapseStrategy = new IntFloatStrategy(maxDoc, size, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores, boostDocsMap);
+ this.collapseStrategy = new IntFloatStrategy(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, groupHeadSelector, this.needsScores, boostDocsMap);
break;
}
default: {
@@ -1243,8 +1248,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int globalDoc = -1;
int nullScoreIndex = 0;
IntIntHashMap cmap = collapseStrategy.getCollapseMap();
- int[] docs = collapseStrategy.getDocs();
- float[] scores = collapseStrategy.getScores();
+ IntFloatMap scores = collapseStrategy.getScores();
FloatArrayList nullScores = collapseStrategy.getNullScores();
MergeBoost mergeBoost = collapseStrategy.getMergeBoost();
float nullScore = collapseStrategy.getNullScore();
@@ -1272,7 +1276,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
if(collapseValue != nullValue) {
int pointer = cmap.get(collapseValue);
- dummy.score = scores[pointer];
+ dummy.score = scores.get(pointer);
} else if (mergeBoost != null && mergeBoost.boost(globalDoc)) {
//Its an elevated doc so no score is needed
dummy.score = 0F;
@@ -1293,6 +1297,10 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
}
+ private static PrimitiveMapFactory getMapFactory() {
+ return PrimitiveMapFactory.newHashBasedFactory();
+ }
+
private static class CollectorFactory {
/** @see #isNumericCollapsible */
private final static EnumSet<NumberType> NUMERIC_COLLAPSIBLE_TYPES = EnumSet.of(NumberType.INTEGER,
@@ -1363,11 +1371,12 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int maxDoc = searcher.maxDoc();
int leafCount = searcher.getTopReaderContext().leaves().size();
+ PrimitiveMapFactory mapFactory = getMapFactory();
if (GroupHeadSelectorType.SCORE.equals(groupHeadSelector.type)) {
if (collapseFieldType instanceof StrField) {
- return new OrdScoreCollector(maxDoc, leafCount, docValuesProducer, nullPolicy, boostDocs, searcher);
+ return new OrdScoreCollector(maxDoc, leafCount, mapFactory, docValuesProducer, nullPolicy, boostDocs, searcher);
} else if (isNumericCollapsible(collapseFieldType)) {
@@ -1399,6 +1408,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
return new OrdFieldValueCollector(maxDoc,
leafCount,
+ mapFactory,
docValuesProducer,
nullPolicy,
groupHeadSelector,
@@ -1429,6 +1439,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
return new IntFieldValueCollector(maxDoc,
size,
+ mapFactory,
leafCount,
nullValue,
nullPolicy,
@@ -1494,11 +1505,11 @@ public class CollapsingQParserPlugin extends QParserPlugin {
*/
private static abstract class OrdFieldValueStrategy {
protected int nullPolicy;
- protected int[] ords;
+ protected IntIntMap ords;
protected Scorable scorer;
protected FloatArrayList nullScores;
protected float nullScore;
- protected float[] scores;
+ protected IntFloatMap scores;
protected FixedBitSet collapsedSet;
protected int nullDoc = -1;
protected boolean needsScores;
@@ -1512,13 +1523,13 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public abstract void setNextReader(LeafReaderContext context) throws IOException;
public OrdFieldValueStrategy(int maxDoc,
- int[] ords,
+ int numValues,
+ PrimitiveMapFactory mapFactory,
int nullPolicy,
boolean needsScores,
IntIntHashMap boostDocsMap,
- SortedDocValues values) {
- this.ords = ords;
- Arrays.fill(ords, -1);
+ SortedDocValues sortedDocValues) {
+ this.ords = mapFactory.newIntIntMap(numValues, -1);
this.nullPolicy = nullPolicy;
this.needsScores = needsScores;
this.collapsedSet = new FixedBitSet(maxDoc);
@@ -1554,7 +1565,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
for(int i=0; i<s; i++) {
int ord = boostOrds.get(i);
if(ord > -1) {
- ords[ord] = -1;
+ ords.remove(ord);
}
collapsedSet.set(boostDocs.get(i));
}
@@ -1562,12 +1573,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
mergeBoost.reset();
}
- for(int i=0; i<ords.length; i++) {
- int doc = ords[i];
- if(doc > -1) {
- collapsedSet.set(doc);
- }
- }
+ ords.forEachValue(doc -> collapsedSet.set(doc));
return collapsedSet;
}
@@ -1584,7 +1590,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
return this.nullScore;
}
- public float[] getScores() {
+ public IntFloatMap getScores() {
return scores;
}
}
@@ -1598,32 +1604,32 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private NumericDocValues minMaxValues;
private IntCompare comp;
private int nullVal;
- private int[] ordVals;
+ private IntIntMap ordVals;
public OrdIntStrategy(int maxDoc,
int nullPolicy,
- int[] ords,
+ int numValues,
+ PrimitiveMapFactory mapFactory,
GroupHeadSelector groupHeadSelector,
boolean needsScores,
IntIntHashMap boostDocs,
SortedDocValues values) throws IOException {
- super(maxDoc, ords, nullPolicy, needsScores, boostDocs, values);
+ super(maxDoc, numValues, mapFactory, nullPolicy, needsScores, boostDocs, values);
this.field = groupHeadSelector.selectorText;
- this.ordVals = new int[ords.length];
assert GroupHeadSelectorType.MIN_MAX.contains(groupHeadSelector.type);
if (GroupHeadSelectorType.MAX.equals(groupHeadSelector.type)) {
comp = new MaxIntComp();
- Arrays.fill(ordVals, Integer.MIN_VALUE);
+ this.ordVals = mapFactory.newIntIntMap(numValues, Integer.MIN_VALUE);
} else {
comp = new MinIntComp();
- Arrays.fill(ordVals, Integer.MAX_VALUE);
+ this.ordVals = mapFactory.newIntIntMap(numValues, Integer.MAX_VALUE);
this.nullVal = Integer.MAX_VALUE;
}
if(needsScores) {
- this.scores = new float[ords.length];
+ this.scores = mapFactory.newIntFloatMap(numValues, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -1650,11 +1656,11 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
if(ord > -1) {
- if(comp.test(currentVal, ordVals[ord])) {
- ords[ord] = globalDoc;
- ordVals[ord] = currentVal;
+ if(comp.test(currentVal, ordVals.get(ord))) {
+ ords.set(ord, globalDoc);
+ ordVals.set(ord, currentVal);
if(needsScores) {
- scores[ord] = scorer.score();
+ scores.set(ord, scorer.score());
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -1684,33 +1690,33 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private NumericDocValues minMaxValues;
private FloatCompare comp;
private float nullVal;
- private float[] ordVals;
+ private IntFloatMap ordVals;
public OrdFloatStrategy(int maxDoc,
int nullPolicy,
- int[] ords,
+ int numValues,
+ PrimitiveMapFactory mapFactory,
GroupHeadSelector groupHeadSelector,
boolean needsScores,
IntIntHashMap boostDocs,
SortedDocValues values) throws IOException {
- super(maxDoc, ords, nullPolicy, needsScores, boostDocs, values);
+ super(maxDoc, numValues, mapFactory, nullPolicy, needsScores, boostDocs, values);
this.field = groupHeadSelector.selectorText;
- this.ordVals = new float[ords.length];
-
+
assert GroupHeadSelectorType.MIN_MAX.contains(groupHeadSelector.type);
if (GroupHeadSelectorType.MAX.equals(groupHeadSelector.type)) {
comp = new MaxFloatComp();
- Arrays.fill(ordVals, -Float.MAX_VALUE);
+ this.ordVals = mapFactory.newIntFloatMap(numValues, -Float.MAX_VALUE);
this.nullVal = -Float.MAX_VALUE;
} else {
comp = new MinFloatComp();
- Arrays.fill(ordVals, Float.MAX_VALUE);
+ this.ordVals = mapFactory.newIntFloatMap(numValues, Float.MAX_VALUE);
this.nullVal = Float.MAX_VALUE;
}
if(needsScores) {
- this.scores = new float[ords.length];
+ this.scores = mapFactory.newIntFloatMap(numValues, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -1739,11 +1745,11 @@ public class CollapsingQParserPlugin extends QParserPlugin {
float currentVal = Float.intBitsToFloat(currentMinMax);
if(ord > -1) {
- if(comp.test(currentVal, ordVals[ord])) {
- ords[ord] = globalDoc;
- ordVals[ord] = currentVal;
+ if(comp.test(currentVal, ordVals.get(ord))) {
+ ords.set(ord, globalDoc);
+ ordVals.set(ord, currentVal);
if(needsScores) {
- scores[ord] = scorer.score();
+ scores.set(ord, scorer.score());
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -1774,31 +1780,31 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private NumericDocValues minMaxVals;
private LongCompare comp;
private long nullVal;
- private long[] ordVals;
+ private IntLongMap ordVals;
public OrdLongStrategy(int maxDoc,
int nullPolicy,
- int[] ords,
+ int numValues,
+ PrimitiveMapFactory mapFactory,
GroupHeadSelector groupHeadSelector,
boolean needsScores,
IntIntHashMap boostDocs, SortedDocValues values) throws IOException {
- super(maxDoc, ords, nullPolicy, needsScores, boostDocs, values);
+ super(maxDoc, numValues, mapFactory, nullPolicy, needsScores, boostDocs, values);
this.field = groupHeadSelector.selectorText;
- this.ordVals = new long[ords.length];
assert GroupHeadSelectorType.MIN_MAX.contains(groupHeadSelector.type);
if (GroupHeadSelectorType.MAX.equals(groupHeadSelector.type)) {
comp = new MaxLongComp();
- Arrays.fill(ordVals, Long.MIN_VALUE);
+ this.ordVals = mapFactory.newIntLongMap(numValues, Long.MIN_VALUE);
} else {
this.nullVal = Long.MAX_VALUE;
comp = new MinLongComp();
- Arrays.fill(ordVals, Long.MAX_VALUE);
+ this.ordVals = mapFactory.newIntLongMap(numValues, Long.MAX_VALUE);
}
if(needsScores) {
- this.scores = new float[ords.length];
+ this.scores = mapFactory.newIntFloatMap(numValues, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -1825,11 +1831,11 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
if(ord > -1) {
- if(comp.test(currentVal, ordVals[ord])) {
- ords[ord] = globalDoc;
- ordVals[ord] = currentVal;
+ if(comp.test(currentVal, ordVals.get(ord))) {
+ ords.set(ord, globalDoc);
+ ordVals.set(ord, currentVal);
if(needsScores) {
- scores[ord] = scorer.score();
+ scores.set(ord, scorer.score());
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -1859,14 +1865,15 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private float nullVal;
private ValueSource valueSource;
private FunctionValues functionValues;
- private float[] ordVals;
+ private IntFloatMap ordVals;
private Map rcontext;
private final CollapseScore collapseScore = new CollapseScore();
private boolean needsScores4Collapsing;
public OrdValueSourceStrategy(int maxDoc,
int nullPolicy,
- int[] ords,
+ int numValue,
+ PrimitiveMapFactory mapFactory,
GroupHeadSelector groupHeadSelector,
boolean needsScores4Collapsing,
boolean needsScores,
@@ -1874,27 +1881,26 @@ public class CollapsingQParserPlugin extends QParserPlugin {
FunctionQuery funcQuery,
IndexSearcher searcher,
SortedDocValues values) throws IOException {
- super(maxDoc, ords, nullPolicy, needsScores, boostDocs, values);
+ super(maxDoc, numValue, mapFactory, nullPolicy, needsScores, boostDocs, values);
this.needsScores4Collapsing = needsScores4Collapsing;
this.valueSource = funcQuery.getValueSource();
this.rcontext = ValueSource.newContext(searcher);
- this.ordVals = new float[ords.length];
assert GroupHeadSelectorType.MIN_MAX.contains(groupHeadSelector.type);
if (GroupHeadSelectorType.MAX.equals(groupHeadSelector.type)) {
comp = new MaxFloatComp();
- Arrays.fill(ordVals, -Float.MAX_VALUE );
+ this.ordVals = mapFactory.newIntFloatMap(numValue, -Float.MAX_VALUE);
} else {
this.nullVal = Float.MAX_VALUE;
comp = new MinFloatComp();
- Arrays.fill(ordVals, Float.MAX_VALUE);
+ this.ordVals = mapFactory.newIntFloatMap(numValue, Float.MAX_VALUE);
}
collapseScore.setupIfNeeded(groupHeadSelector, rcontext);
if(this.needsScores) {
- this.scores = new float[ords.length];
+ this.scores = mapFactory.newIntFloatMap(numValue, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -1921,14 +1927,14 @@ public class CollapsingQParserPlugin extends QParserPlugin {
float currentVal = functionValues.floatVal(contextDoc);
if(ord > -1) {
- if(comp.test(currentVal, ordVals[ord])) {
- ords[ord] = globalDoc;
- ordVals[ord] = currentVal;
+ if(comp.test(currentVal, ordVals.get(ord))) {
+ ords.set(ord, globalDoc);
+ ordVals.set(ord, currentVal);
if(needsScores) {
if (!needsScores4Collapsing) {
score = scorer.score();
}
- scores[ord] = score;
+ scores.set(ord, score);
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -1968,7 +1974,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public OrdSortSpecStrategy(int maxDoc,
int nullPolicy,
- int[] ords,
+ int numValues,
+ PrimitiveMapFactory mapFactory,
GroupHeadSelector groupHeadSelector,
boolean needsScores4Collapsing,
boolean needsScores,
@@ -1976,17 +1983,17 @@ public class CollapsingQParserPlugin extends QParserPlugin {
SortSpec sortSpec,
IndexSearcher searcher,
SortedDocValues values) throws IOException {
- super(maxDoc, ords, nullPolicy, needsScores, boostDocs, values);
+ super(maxDoc, numValues, mapFactory, nullPolicy, needsScores, boostDocs, values);
this.needsScores4Collapsing = needsScores4Collapsing;
assert GroupHeadSelectorType.SORT.equals(groupHeadSelector.type);
this.sort = rewriteSort(sortSpec, searcher);
- this.compareState = new SortFieldsCompare(sort.getSort(), ords.length);
+ this.compareState = new SortFieldsCompare(sort.getSort(), numValues);
if (this.needsScores) {
- this.scores = new float[ords.length];
+ this.scores = mapFactory.newIntFloatMap(numValues, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -2017,25 +2024,25 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
if (ord > -1) { // real collapseKey
- if (-1 == ords[ord]) {
+ if (-1 == ords.get(ord)) {
// we've never seen this ord (aka: collapseKey) before, treat it as group head for now
compareState.setGroupValues(ord, contextDoc);
- ords[ord] = globalDoc;
+ ords.set(ord, globalDoc);
if (needsScores) {
if (!needsScores4Collapsing) {
this.score = scorer.score();
}
- scores[ord] = score;
+ scores.set(ord, score);
}
} else {
// test this ord to see if it's a new group leader
if (compareState.testAndSetGroupValues(ord, contextDoc)) {//TODO X
- ords[ord] = globalDoc;
+ ords.set(ord, globalDoc);
if (needsScores) {
if (!needsScores4Collapsing) {
this.score = scorer.score();
}
- scores[ord] = score;
+ scores.set(ord, score);
}
}
}
@@ -2085,12 +2092,12 @@ public class CollapsingQParserPlugin extends QParserPlugin {
protected Scorable scorer;
protected FloatArrayList nullScores;
protected float nullScore;
- protected float[] scores;
+ protected IntFloatMap scores;
protected FixedBitSet collapsedSet;
protected int nullDoc = -1;
protected boolean needsScores;
protected String collapseField;
- protected int[] docs;
+ protected IntIntMap docs;
protected int nullValue;
protected IntArrayList boostDocs;
protected IntArrayList boostKeys;
@@ -2102,6 +2109,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public IntFieldValueStrategy(int maxDoc,
int size,
+ PrimitiveMapFactory mapFactory,
String collapseField,
int nullValue,
int nullPolicy,
@@ -2113,7 +2121,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.needsScores = needsScores;
this.collapsedSet = new FixedBitSet(maxDoc);
this.cmap = new IntIntHashMap(size);
- this.docs = new int[size];
+ this.docs = mapFactory.newIntIntMap(size, 0);
if(boostDocsMap != null) {
this.boosts = true;
this.boostDocs = new IntArrayList();
@@ -2156,7 +2164,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
while(it1.hasNext()) {
IntIntCursor cursor = it1.next();
int pointer = cursor.value;
- collapsedSet.set(docs[pointer]);
+ collapsedSet.set(docs.get(pointer));
}
return collapsedSet;
@@ -2178,11 +2186,11 @@ public class CollapsingQParserPlugin extends QParserPlugin {
return this.nullScore;
}
- public float[] getScores() {
+ public IntFloatMap getScores() {
return scores;
}
- public int[] getDocs() { return docs;}
+ public IntIntMap getDocs() { return docs;}
public MergeBoost getMergeBoost() {
return this.mergeBoost;
@@ -2197,7 +2205,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private final String field;
private NumericDocValues minMaxVals;
- private int[] testValues;
+ private IntIntMap testValues;
private IntCompare comp;
private int nullCompVal;
@@ -2205,6 +2213,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public IntIntStrategy(int maxDoc,
int size,
+ PrimitiveMapFactory mapFactory,
String collapseField,
int nullValue,
int nullPolicy,
@@ -2212,9 +2221,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
boolean needsScores,
IntIntHashMap boostDocs) throws IOException {
- super(maxDoc, size, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
+ super(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
this.field = groupHeadSelector.selectorText;
- this.testValues = new int[size];
+ this.testValues = mapFactory.newIntIntMap(size, 0);
assert GroupHeadSelectorType.MIN_MAX.contains(groupHeadSelector.type);
@@ -2227,7 +2236,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
if(needsScores) {
- this.scores = new float[size];
+ this.scores = mapFactory.newIntFloatMap(size, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -2258,29 +2267,20 @@ public class CollapsingQParserPlugin extends QParserPlugin {
final int idx;
if((idx = cmap.indexOf(collapseKey)) >= 0) {
int pointer = cmap.indexGet(idx);
- if(comp.test(currentVal, testValues[pointer])) {
- testValues[pointer]= currentVal;
- docs[pointer] = globalDoc;
+ if(comp.test(currentVal, testValues.get(pointer))) {
+ testValues.set(pointer, currentVal);
+ docs.set(pointer, globalDoc);
if(needsScores) {
- scores[pointer] = scorer.score();
+ scores.set(pointer, scorer.score());
}
}
} else {
++index;
cmap.put(collapseKey, index);
- if(index == testValues.length) {
- testValues = ArrayUtil.grow(testValues);
- docs = ArrayUtil.grow(docs);
- if(needsScores) {
- scores = ArrayUtil.grow(scores);
- }
- }
-
- testValues[index] = currentVal;
- docs[index] = (globalDoc);
-
+ testValues.set(index, currentVal);
+ docs.set(index, globalDoc);
if(needsScores) {
- scores[index] = scorer.score();
+ scores.set(index, scorer.score());
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -2304,7 +2304,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private final String field;
private NumericDocValues minMaxVals;
- private float[] testValues;
+ private IntFloatMap testValues;
private FloatCompare comp;
private float nullCompVal;
@@ -2312,6 +2312,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public IntFloatStrategy(int maxDoc,
int size,
+ PrimitiveMapFactory mapFactory,
String collapseField,
int nullValue,
int nullPolicy,
@@ -2319,9 +2320,9 @@ public class CollapsingQParserPlugin extends QParserPlugin {
boolean needsScores,
IntIntHashMap boostDocs) throws IOException {
- super(maxDoc, size, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
+ super(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
this.field = groupHeadSelector.selectorText;
- this.testValues = new float[size];
+ this.testValues = mapFactory.newIntFloatMap(size, 0.0f);
assert GroupHeadSelectorType.MIN_MAX.contains(groupHeadSelector.type);
@@ -2334,7 +2335,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
}
if(needsScores) {
- this.scores = new float[size];
+ this.scores = mapFactory.newIntFloatMap(size, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -2367,28 +2368,20 @@ public class CollapsingQParserPlugin extends QParserPlugin {
final int idx;
if((idx = cmap.indexOf(collapseKey)) >= 0) {
int pointer = cmap.indexGet(idx);
- if(comp.test(currentVal, testValues[pointer])) {
- testValues[pointer] = currentVal;
- docs[pointer] = globalDoc;
+ if(comp.test(currentVal, testValues.get(pointer))) {
+ testValues.set(pointer, currentVal);
+ docs.set(pointer, globalDoc);
if(needsScores) {
- scores[pointer] = scorer.score();
+ scores.set(pointer, scorer.score());
}
}
} else {
++index;
cmap.put(collapseKey, index);
- if(index == testValues.length) {
- testValues = ArrayUtil.grow(testValues);
- docs = ArrayUtil.grow(docs);
- if(needsScores) {
- scores = ArrayUtil.grow(scores);
- }
- }
-
- testValues[index] = currentVal;
- docs[index] = globalDoc;
+ testValues.set(index, currentVal);
+ docs.set(index, globalDoc);
if(needsScores) {
- scores[index] = scorer.score();
+ scores.set(index, scorer.score());
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -2415,7 +2408,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private static class IntValueSourceStrategy extends IntFieldValueStrategy {
private FloatCompare comp;
- private float[] testValues;
+ private IntFloatMap testValues;
private float nullCompVal;
private ValueSource valueSource;
@@ -2427,6 +2420,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public IntValueSourceStrategy(int maxDoc,
int size,
+ PrimitiveMapFactory mapFactory,
String collapseField,
int nullValue,
int nullPolicy,
@@ -2437,10 +2431,10 @@ public class CollapsingQParserPlugin extends QParserPlugin {
FunctionQuery funcQuery,
IndexSearcher searcher) throws IOException {
- super(maxDoc, size, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
+ super(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
this.needsScores4Collapsing = needsScores4Collapsing;
- this.testValues = new float[size];
+ this.testValues = mapFactory.newIntFloatMap(size, 0.0f);
this.valueSource = funcQuery.getValueSource();
this.rcontext = ValueSource.newContext(searcher);
@@ -2458,7 +2452,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
collapseScore.setupIfNeeded(groupHeadSelector, rcontext);
if(needsScores) {
- this.scores = new float[size];
+ this.scores = mapFactory.newIntFloatMap(size, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -2490,33 +2484,26 @@ public class CollapsingQParserPlugin extends QParserPlugin {
final int idx;
if((idx = cmap.indexOf(collapseKey)) >= 0) {
int pointer = cmap.indexGet(idx);
- if(comp.test(currentVal, testValues[pointer])) {
- testValues[pointer] = currentVal;
- docs[pointer] = globalDoc;
+ if(comp.test(currentVal, testValues.get(pointer))) {
+ testValues.set(pointer, currentVal);
+ docs.set(pointer, globalDoc);
if(needsScores){
if (!needsScores4Collapsing) {
score = scorer.score();
}
- scores[pointer] = score;
+ scores.set(pointer, score);
}
}
} else {
++index;
cmap.put(collapseKey, index);
- if(index == testValues.length) {
- testValues = ArrayUtil.grow(testValues);
- docs = ArrayUtil.grow(docs);
- if(needsScores) {
- scores = ArrayUtil.grow(scores);
- }
- }
- docs[index] = globalDoc;
- testValues[index] = currentVal;
+ docs.set(index, globalDoc);
+ testValues.set(index, currentVal);
if(needsScores) {
if (!needsScores4Collapsing) {
score = scorer.score();
}
- scores[index] = score;
+ scores.set(index, score);
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -2558,6 +2545,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public IntSortSpecStrategy(int maxDoc,
int size,
+ PrimitiveMapFactory mapFactory,
String collapseField,
int nullValue,
int nullPolicy,
@@ -2568,7 +2556,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
SortSpec sortSpec,
IndexSearcher searcher) throws IOException {
- super(maxDoc, size, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
+ super(maxDoc, size, mapFactory, collapseField, nullValue, nullPolicy, needsScores, boostDocs);
this.needsScores4Collapsing = needsScores4Collapsing;
assert GroupHeadSelectorType.SORT.equals(groupHeadSelector.type);
@@ -2578,7 +2566,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.compareState = new SortFieldsCompare(sort.getSort(), size);
if(needsScores) {
- this.scores = new float[size];
+ this.scores = mapFactory.newIntFloatMap(size, 0.0f);
if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
nullScores = new FloatArrayList();
}
@@ -2616,32 +2604,25 @@ public class CollapsingQParserPlugin extends QParserPlugin {
// we've seen this collapseKey before, test to see if it's a new group leader
int pointer = cmap.indexGet(idx);
if (compareState.testAndSetGroupValues(pointer, contextDoc)) {
- docs[pointer] = globalDoc;
+ docs.set(pointer, globalDoc);
if (needsScores) {
if (!needsScores4Collapsing) {
score = scorer.score();
}
- scores[pointer] = score;
+ scores.set(pointer, score);
}
}
} else {
// we've never seen this collapseKey before, treat it as group head for now
++index;
cmap.put(collapseKey, index);
- if (index == docs.length) {
- docs = ArrayUtil.grow(docs);
- compareState.grow(docs.length);
- if(needsScores) {
- scores = ArrayUtil.grow(scores);
- }
- }
- docs[index] = globalDoc;
+ docs.set(index, globalDoc);
compareState.setGroupValues(index, contextDoc);
if(needsScores) {
if (!needsScores4Collapsing) {
score = scorer.score();
}
- scores[index] = score;
+ scores.set(index, score);
}
}
} else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
@@ -2794,7 +2775,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
*/
public void setGroupValues(int collapseKey, int contextDoc) throws IOException {
assert 0 <= collapseKey : "negative collapseKey";
- assert collapseKey < groupHeadValues.length : "collapseKey too big -- need to grow array?";
+ if (collapseKey >= groupHeadValues.length) grow(collapseKey);
setGroupValues(getOrInitGroupHeadValues(collapseKey), contextDoc);
}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/FloatConsumer.java b/solr/core/src/java/org/apache/solr/util/numeric/FloatConsumer.java
new file mode 100644
index 0000000..05b24e9
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/FloatConsumer.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+@FunctionalInterface
+public interface FloatConsumer {
+ void accept(float f);
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntFloatArrayBasedMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntFloatArrayBasedMap.java
new file mode 100644
index 0000000..592d525
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntFloatArrayBasedMap.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.Arrays;
+
+import org.apache.lucene.util.ArrayUtil;
+
+public class IntFloatArrayBasedMap implements IntFloatMap {
+
+ private int size;
+ private float[] keyValues;
+ private float emptyValue;
+
+ public IntFloatArrayBasedMap(int initialSize, float emptyValue) {
+ this.size = initialSize;
+ this.keyValues = new float[initialSize];
+ this.emptyValue = emptyValue;
+ if (emptyValue != 0) {
+ Arrays.fill(keyValues, emptyValue);
+ }
+ }
+
+ @Override
+ public void set(int key, float value) {
+ if (key >= size) {
+ keyValues = ArrayUtil.grow(keyValues);
+ if (emptyValue != 0) {
+ for (int i = size; i < keyValues.length; i++) {
+ keyValues[i] = emptyValue;
+ }
+ }
+ size = keyValues.length;
+ }
+ keyValues[key] = value;
+ }
+
+ @Override
+ public float get(int key) {
+ if (key >= size) {
+ return emptyValue;
+ }
+ return keyValues[key];
+ }
+
+ @Override
+ public void forEachValue(FloatConsumer consumer) {
+ for (float val: keyValues) {
+ if (val != emptyValue) {
+ consumer.accept(val);
+ }
+ }
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntFloatHashMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntFloatHashMap.java
new file mode 100644
index 0000000..4fbe3d6
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntFloatHashMap.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import com.carrotsearch.hppc.procedures.IntFloatProcedure;
+
+public class IntFloatHashMap implements IntFloatMap {
+ private com.carrotsearch.hppc.IntFloatHashMap hashMap;
+ private float emptyValue;
+
+ public IntFloatHashMap(int initialSize, float emptyValue) {
+ this.hashMap = new com.carrotsearch.hppc.IntFloatHashMap();
+ this.emptyValue = emptyValue;
+ }
+ @Override
+ public final void set(int key, float value) {
+ this.hashMap.put(key, value);
+ }
+
+ @Override
+ public final float get(int key) {
+ return this.hashMap.getOrDefault(key, emptyValue);
+ }
+
+ @Override
+ public void forEachValue(FloatConsumer consumer) {
+ this.hashMap.forEach((IntFloatProcedure) (key, value) -> consumer.accept(value));
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntFloatMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntFloatMap.java
new file mode 100644
index 0000000..e847e16
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntFloatMap.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.function.IntConsumer;
+
+public interface IntFloatMap {
+ void set(int key, float value);
+ float get(int key);
+ void forEachValue(FloatConsumer consumer);
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntIntArrayBasedMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntIntArrayBasedMap.java
new file mode 100644
index 0000000..bd695b7
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntIntArrayBasedMap.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.function.IntConsumer;
+
+import org.apache.lucene.util.ArrayUtil;
+
+public class IntIntArrayBasedMap implements IntIntMap {
+
+ private int size;
+ private int[] keyValues;
+ private int emptyValue;
+
+ public IntIntArrayBasedMap(int initialSize, int emptyValue) {
+ this.size = initialSize;
+ this.keyValues = new int[initialSize];
+ this.emptyValue = emptyValue;
+ if (emptyValue != 0) {
+ Arrays.fill(keyValues, emptyValue);
+ }
+ }
+
+ @Override
+ public void set(int key, int value) {
+ if (key >= size) {
+ keyValues = ArrayUtil.grow(keyValues);
+ if (emptyValue != 0) {
+ for (int i = size; i < keyValues.length; i++) {
+ keyValues[i] = emptyValue;
+ }
+ }
+ size = keyValues.length;
+ }
+ keyValues[key] = value;
+ }
+
+ @Override
+ public int get(int key) {
+ if (key >= size) {
+ return emptyValue;
+ }
+ return keyValues[key];
+ }
+
+ @Override
+ public void forEachValue(IntConsumer consumer) {
+ for (int val: keyValues) {
+ if (val != emptyValue) {
+ consumer.accept(val);
+ }
+ }
+ }
+
+ @Override
+ public void remove(int key) {
+ if (key < size) keyValues[key] = emptyValue;
+ }
+
+ @Override
+ public int size() {
+ return keyValues.length;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntIntHashMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntIntHashMap.java
new file mode 100644
index 0000000..d652055
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntIntHashMap.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.function.IntConsumer;
+
+import com.carrotsearch.hppc.cursors.IntCursor;
+import com.carrotsearch.hppc.procedures.IntIntProcedure;
+
+public class IntIntHashMap implements IntIntMap {
+ private com.carrotsearch.hppc.IntIntHashMap hashMap;
+ private int emptyValue;
+
+ public IntIntHashMap(int initialSize, int emptyValue) {
+ this.hashMap = new com.carrotsearch.hppc.IntIntHashMap();
+ this.emptyValue = emptyValue;
+ }
+
+ @Override
+ public final void set(int key, int value) {
+ this.hashMap.put(key, value);
+ }
+
+ @Override
+ public final int get(int key) {
+ return this.hashMap.getOrDefault(key, emptyValue);
+ }
+
+ @Override
+ public void forEachValue(IntConsumer consumer) {
+ for (IntCursor ord : hashMap.values()) {
+ consumer.accept(ord.value);
+ }
+ }
+
+ @Override
+ public void remove(int key) {
+ this.hashMap.remove(key);
+ }
+
+ @Override
+ public int size() {
+ return hashMap.size();
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntIntMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntIntMap.java
new file mode 100644
index 0000000..0366ffe
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntIntMap.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.function.Consumer;
+import java.util.function.IntConsumer;
+
+public interface IntIntMap {
+ void set(int key, int value);
+ int get(int key);
+ void forEachValue(IntConsumer consumer);
+ void remove(int key);
+ int size();
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntLongArrayBasedMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntLongArrayBasedMap.java
new file mode 100644
index 0000000..155b8be
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntLongArrayBasedMap.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.Arrays;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.apache.lucene.util.ArrayUtil;
+
+public class IntLongArrayBasedMap implements IntLongMap {
+
+ private int size;
+ private long[] keyValues;
+ private long emptyValue;
+
+ public IntLongArrayBasedMap(int initialSize, long emptyValue) {
+ this.size = initialSize;
+ this.keyValues = new long[initialSize];
+ this.emptyValue = emptyValue;
+ if (emptyValue != 0) {
+ Arrays.fill(keyValues, emptyValue);
+ }
+ }
+
+ @Override
+ public void set(int key, long value) {
+ if (key >= size) {
+ keyValues = ArrayUtil.grow(keyValues);
+ if (emptyValue != 0) {
+ for (int i = size; i < keyValues.length; i++) {
+ keyValues[i] = emptyValue;
+ }
+ }
+ size = keyValues.length;
+ }
+ keyValues[key] = value;
+ }
+
+ @Override
+ public long get(int key) {
+ if (key >= size) {
+ return emptyValue;
+ }
+ return keyValues[key];
+ }
+
+ @Override
+ public void forEachValue(LongConsumer consumer) {
+ for (long val: keyValues) {
+ if (val != emptyValue) {
+ consumer.accept(val);
+ }
+ }
+ }
+
+ @Override
+ public void remove(int key) {
+ if (key < size) keyValues[key] = emptyValue;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntLongHashMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntLongHashMap.java
new file mode 100644
index 0000000..cbe4e21
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntLongHashMap.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.function.LongConsumer;
+
+import com.carrotsearch.hppc.procedures.IntLongProcedure;
+
+public class IntLongHashMap implements IntLongMap {
+ private com.carrotsearch.hppc.IntLongHashMap hashMap;
+ private long emptyValue;
+
+ public IntLongHashMap(int initialSize, long emptyValue) {
+ this.hashMap = new com.carrotsearch.hppc.IntLongHashMap(initialSize);
+ this.emptyValue = emptyValue;
+ }
+ @Override
+ public void set(int key, long value) {
+ this.hashMap.put(key, value);
+ }
+
+ @Override
+ public long get(int key) {
+ return this.hashMap.getOrDefault(key, emptyValue);
+ }
+
+ @Override
+ public void forEachValue(LongConsumer consumer) {
+ this.hashMap.forEach((IntLongProcedure) (key, value) -> consumer.accept(value));
+ }
+
+ @Override
+ public void remove(int key) {
+ this.hashMap.remove(key);
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/IntLongMap.java b/solr/core/src/java/org/apache/solr/util/numeric/IntLongMap.java
new file mode 100644
index 0000000..48c2828
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/IntLongMap.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+public interface IntLongMap {
+ void set(int key, long value);
+ long get(int key);
+ void forEachValue(LongConsumer consumer);
+ void remove(int key);
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/PrimitiveMapFactory.java b/solr/core/src/java/org/apache/solr/util/numeric/PrimitiveMapFactory.java
new file mode 100644
index 0000000..81702f5
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/PrimitiveMapFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.util.numeric;
+
+public interface PrimitiveMapFactory {
+ IntIntMap newIntIntMap(int initialSize, int emptyValue);
+ IntFloatMap newIntFloatMap(int initialSize, float emptyValue);
+ IntLongMap newIntLongMap(int initialSize, long emptyValue);
+
+ static PrimitiveMapFactory newArrayBasedFactory() {
+ return new PrimitiveMapFactory() {
+ @Override
+ public IntIntMap newIntIntMap(int initialSize, int emptyValue) {
+ return new IntIntArrayBasedMap(initialSize, emptyValue);
+ }
+
+ @Override
+ public IntFloatMap newIntFloatMap(int initialSize, float emptyValue) {
+ return new IntFloatArrayBasedMap(initialSize, emptyValue);
+ }
+
+ @Override
+ public IntLongMap newIntLongMap(int initialSize, long emptyValue) {
+ return new IntLongArrayBasedMap(initialSize, emptyValue);
+ }
+ };
+ }
+
+ static PrimitiveMapFactory newHashBasedFactory() {
+ return new PrimitiveMapFactory() {
+ @Override
+ public IntIntMap newIntIntMap(int initialSize, int emptyValue) {
+ return new IntIntHashMap(4, emptyValue);
+ }
+
+ @Override
+ public IntFloatMap newIntFloatMap(int initialSize, float emptyValue) {
+ return new IntFloatHashMap(4, emptyValue);
+ }
+
+ @Override
+ public IntLongMap newIntLongMap(int initialSize, long emptyValue) {
+ return new IntLongHashMap(4, emptyValue);
+ }
+ };
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/util/numeric/package-info.java b/solr/core/src/java/org/apache/solr/util/numeric/package-info.java
new file mode 100644
index 0000000..baa6a58
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/numeric/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Collections of simple, high-performance classes for numeric.
+ *
+ */
+package org.apache.solr.util.numeric;
+