improve multi value field cache handling both in terms of memory usage and GC behavior

This commit is contained in:
kimchy 2011-01-10 20:18:12 +02:00
parent cb8ceb1a39
commit 233ed1f8c6
7 changed files with 364 additions and 260 deletions

View File

@ -61,36 +61,38 @@ public class MultiValueDoubleFieldData extends DoubleFieldData {
}
@Override public boolean hasValue(int docId) {
return ordinals[docId] != null;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
return true;
}
}
return false;
}
@Override public void forEachValueInDoc(int docId, StringValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, Double.toString(values[docOrder]));
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, Double.toString(values[loc]));
}
}
}
@Override public void forEachValueInDoc(int docId, DoubleValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public void forEachValueInDoc(int docId, ValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@ -99,26 +101,37 @@ public class MultiValueDoubleFieldData extends DoubleFieldData {
}
@Override public double value(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
return values[loc];
}
}
return values[docOrders[0]];
return 0;
}
@Override public double[] values(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return EMPTY_DOUBLE_ARRAY;
}
double[] doubles;
if (docOrders.length < VALUE_CACHE_SIZE) {
doubles = valuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
doubles = valuesCache.get().get()[length];
} else {
doubles = new double[docOrders.length];
doubles = new double[length];
}
for (int i = 0; i < docOrders.length; i++) {
doubles[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
doubles[i++] = values[loc];
}
}
return doubles;
}

View File

@ -72,77 +72,99 @@ public class MultiValueFloatFieldData extends FloatFieldData {
}
@Override public boolean hasValue(int docId) {
return ordinals[docId] != null;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
return true;
}
}
return false;
}
@Override public void forEachValueInDoc(int docId, StringValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, Float.toString(values[docOrder]));
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, Float.toString(values[loc]));
}
}
}
@Override public void forEachValueInDoc(int docId, DoubleValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public void forEachValueInDoc(int docId, ValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public double[] doubleValues(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
}
double[] doubles;
if (docOrders.length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[length];
} else {
doubles = new double[docOrders.length];
doubles = new double[length];
}
for (int i = 0; i < docOrders.length; i++) {
doubles[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
doubles[i++] = values[loc];
}
}
return doubles;
}
@Override public float value(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
return values[loc];
}
}
return values[docOrders[0]];
return 0;
}
@Override public float[] values(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return EMPTY_FLOAT_ARRAY;
}
float[] floats;
if (docOrders.length < VALUE_CACHE_SIZE) {
floats = valuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
floats = valuesCache.get().get()[length];
} else {
floats = new float[docOrders.length];
floats = new float[length];
}
for (int i = 0; i < docOrders.length; i++) {
floats[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
floats[i++] = values[loc];
}
}
return floats;
}

View File

@ -72,77 +72,99 @@ public class MultiValueIntFieldData extends IntFieldData {
}
@Override public boolean hasValue(int docId) {
return ordinals[docId] != null;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
return true;
}
}
return false;
}
@Override public void forEachValueInDoc(int docId, StringValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, Integer.toString(values[docOrder]));
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, Integer.toString(values[loc]));
}
}
}
@Override public void forEachValueInDoc(int docId, DoubleValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public void forEachValueInDoc(int docId, ValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public double[] doubleValues(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
}
double[] doubles;
if (docOrders.length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[length];
} else {
doubles = new double[docOrders.length];
doubles = new double[length];
}
for (int i = 0; i < docOrders.length; i++) {
doubles[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
doubles[i++] = values[loc];
}
}
return doubles;
}
@Override public int value(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
return values[loc];
}
}
return values[docOrders[0]];
return 0;
}
@Override public int[] values(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return EMPTY_INT_ARRAY;
}
int[] ints;
if (docOrders.length < VALUE_CACHE_SIZE) {
ints = valuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
ints = valuesCache.get().get()[length];
} else {
ints = new int[docOrders.length];
ints = new int[length];
}
for (int i = 0; i < docOrders.length; i++) {
ints[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
ints[i++] = values[loc];
}
}
return ints;
}

View File

@ -88,120 +88,149 @@ public class MultiValueLongFieldData extends LongFieldData {
}
@Override public boolean hasValue(int docId) {
return ordinals[docId] != null;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
return true;
}
}
return false;
}
@Override public void forEachValueInDoc(int docId, StringValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, Long.toString(values[docOrder]));
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, Long.toString(values[loc]));
}
}
}
@Override public void forEachValueInDoc(int docId, DoubleValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public void forEachValueInDoc(int docId, ValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public void forEachValueInDoc(int docId, DateValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
MutableDateTime dateTime = dateTimeCache.get().get();
for (int docOrder : docOrders) {
dateTime.setMillis(values[docOrder]);
proc.onValue(docId, dateTime);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
dateTime.setMillis(values[loc]);
proc.onValue(docId, dateTime);
}
}
}
@Override public void forEachValueInDoc(int docId, MutableDateTime dateTime, DateValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
dateTime.setMillis(values[docOrder]);
proc.onValue(docId, dateTime);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
dateTime.setMillis(values[loc]);
proc.onValue(docId, dateTime);
}
}
}
@Override public MutableDateTime[] dates(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return EMPTY_DATETIME_ARRAY;
}
MutableDateTime[] dates;
if (docOrders.length < VALUE_CACHE_SIZE) {
dates = dateTimesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
dates = dateTimesCache.get().get()[length];
} else {
dates = new MutableDateTime[docOrders.length];
dates = new MutableDateTime[length];
for (int i = 0; i < dates.length; i++) {
dates[i] = new MutableDateTime();
}
}
for (int i = 0; i < docOrders.length; i++) {
dates[i].setMillis(values[docOrders[i]]);
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
dates[i++].setMillis(values[loc]);
}
}
return dates;
}
@Override public double[] doubleValues(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
}
double[] doubles;
if (docOrders.length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[length];
} else {
doubles = new double[docOrders.length];
doubles = new double[length];
}
for (int i = 0; i < docOrders.length; i++) {
doubles[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
doubles[i++] = values[loc];
}
}
return doubles;
}
@Override public long value(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
return values[loc];
}
}
return values[docOrders[0]];
return 0;
}
@Override public long[] values(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return EMPTY_LONG_ARRAY;
}
long[] longs;
if (docOrders.length < VALUE_CACHE_SIZE) {
longs = valuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
longs = valuesCache.get().get()[length];
} else {
longs = new long[docOrders.length];
longs = new long[length];
}
for (int i = 0; i < docOrders.length; i++) {
longs[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
longs[i++] = values[loc];
}
}
return longs;
}

View File

@ -72,77 +72,99 @@ public class MultiValueShortFieldData extends ShortFieldData {
}
@Override public boolean hasValue(int docId) {
return ordinals[docId] != null;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
return true;
}
}
return false;
}
@Override public void forEachValueInDoc(int docId, StringValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, Short.toString(values[docOrder]));
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, Short.toString(values[loc]));
}
}
}
@Override public void forEachValueInDoc(int docId, DoubleValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public void forEachValueInDoc(int docId, ValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public double[] doubleValues(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return DoubleFieldData.EMPTY_DOUBLE_ARRAY;
}
double[] doubles;
if (docOrders.length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
doubles = doublesValuesCache.get().get()[length];
} else {
doubles = new double[docOrders.length];
doubles = new double[length];
}
for (int i = 0; i < docOrders.length; i++) {
doubles[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
doubles[i++] = values[loc];
}
}
return doubles;
}
@Override public short value(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
return values[loc];
}
}
return values[docOrders[0]];
return 0;
}
@Override public short[] values(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return EMPTY_SHORT_ARRAY;
}
short[] shorts;
if (docOrders.length < VALUE_CACHE_SIZE) {
shorts = valuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
shorts = valuesCache.get().get()[length];
} else {
shorts = new short[docOrders.length];
shorts = new short[length];
}
for (int i = 0; i < docOrders.length; i++) {
shorts[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
shorts[i++] = values[loc];
}
}
return shorts;
}

View File

@ -62,40 +62,55 @@ public class MultiValueStringFieldData extends StringFieldData {
}
@Override public boolean hasValue(int docId) {
return ordinals[docId] != null;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
return true;
}
}
return false;
}
@Override public void forEachValueInDoc(int docId, StringValueInDocProc proc) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return;
}
for (int docOrder : docOrders) {
proc.onValue(docId, values[docOrder]);
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
proc.onValue(docId, values[loc]);
}
}
}
@Override public String value(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
return null;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
return values[loc];
}
}
return values[docOrders[0]];
return null;
}
@Override public String[] values(int docId) {
int[] docOrders = ordinals[docId];
if (docOrders == null) {
int length = 0;
for (int[] ordinal : ordinals) {
if (ordinal[docId] != 0) {
length++;
}
}
if (length == 0) {
return Strings.EMPTY_ARRAY;
}
String[] strings;
if (docOrders.length < VALUE_CACHE_SIZE) {
strings = valuesCache.get().get()[docOrders.length];
if (length < VALUE_CACHE_SIZE) {
strings = valuesCache.get().get()[length];
} else {
strings = new String[docOrders.length];
strings = new String[length];
}
for (int i = 0; i < docOrders.length; i++) {
strings[i] = values[docOrders[i]];
int i = 0;
for (int[] ordinal : ordinals) {
int loc = ordinal[docId];
if (loc != 0) {
strings[i++] = values[loc];
}
}
return strings;
}

View File

@ -27,7 +27,7 @@ import org.apache.lucene.util.StringHelper;
import org.elasticsearch.index.field.data.FieldData;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
/**
* @author kimchy (shay.banon)
@ -40,8 +40,8 @@ public class FieldDataLoader {
loader.init();
field = StringHelper.intern(field);
int[] ordinals = new int[reader.maxDoc()];
int[][] multiValueOrdinals = null;
ArrayList<int[]> ordinals = new ArrayList<int[]>();
ordinals.add(new int[reader.maxDoc()]);
int t = 1; // current term number
@ -55,46 +55,23 @@ public class FieldDataLoader {
termDocs.seek(termEnum);
while (termDocs.next()) {
int doc = termDocs.doc();
if (multiValueOrdinals != null) {
int[] ordinalPerDoc = multiValueOrdinals[doc];
if (ordinalPerDoc == null) {
ordinalPerDoc = new int[1];
ordinalPerDoc[0] = t;
multiValueOrdinals[doc] = ordinalPerDoc;
} else {
ordinalPerDoc = Arrays.copyOf(ordinalPerDoc, ordinalPerDoc.length + 1);
ordinalPerDoc[ordinalPerDoc.length - 1] = t;
multiValueOrdinals[doc] = ordinalPerDoc;
}
} else {
int ordinal = ordinals[doc];
if (ordinal == 0) { // still not multi valued...
ordinals[doc] = t;
} else {
// move to multi valued
multiValueOrdinals = new int[reader.maxDoc()][];
for (int i = 0; i < ordinals.length; i++) {
ordinal = ordinals[i];
if (ordinal != 0) {
multiValueOrdinals[i] = new int[1];
multiValueOrdinals[i][0] = ordinal;
}
}
// now put the current "t" value
int[] ordinalPerDoc = multiValueOrdinals[doc];
if (ordinalPerDoc == null) {
ordinalPerDoc = new int[1];
ordinalPerDoc[0] = t;
multiValueOrdinals[doc] = ordinalPerDoc;
} else {
ordinalPerDoc = Arrays.copyOf(ordinalPerDoc, ordinalPerDoc.length + 1);
ordinalPerDoc[ordinalPerDoc.length - 1] = t;
multiValueOrdinals[doc] = ordinalPerDoc;
}
boolean found = false;
for (int i = 0; i < ordinals.size(); i++) {
int[] ordinal = ordinals.get(i);
if (ordinal[doc] == 0) {
// we found a spot, use it
ordinal[doc] = t;
found = true;
break;
}
}
if (!found) {
// did not find one, increase by one and redo
int[] ordinal = new int[reader.maxDoc()];
ordinals.add(ordinal);
ordinal[doc] = t;
}
}
t++;
} while (termEnum.next());
} catch (RuntimeException e) {
@ -108,10 +85,14 @@ public class FieldDataLoader {
termEnum.close();
}
if (multiValueOrdinals != null) {
return loader.buildMultiValue(field, multiValueOrdinals);
if (ordinals.size() == 1) {
return loader.buildSingleValue(field, ordinals.get(0));
} else {
return loader.buildSingleValue(field, ordinals);
int[][] nativeOrdinals = new int[ordinals.size()][];
for (int i = 0; i < nativeOrdinals.length; i++) {
nativeOrdinals[i] = ordinals.get(i);
}
return loader.buildMultiValue(field, nativeOrdinals);
}
}