move sorting to be done using the new fielddata cache, and not using lucene built in FieldCache

This commit is contained in:
kimchy 2010-07-08 14:42:35 +03:00
parent 97b5b41522
commit 8d669ff54e
31 changed files with 942 additions and 145 deletions

View File

@ -64,7 +64,7 @@ public abstract class AbstractConcurrentMapFieldDataCache extends AbstractIndexC
}
@Override public FieldData cache(FieldData.Type type, IndexReader reader, String fieldName) throws IOException {
return cache(type.fieldDataClass, reader, fieldName);
return cache(type.fieldDataClass(), reader, fieldName);
}
@Override public <T extends FieldData> T cache(Class<T> type, IndexReader reader, String fieldName) throws IOException {

View File

@ -20,14 +20,23 @@
package org.elasticsearch.index.field.data;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;
import org.elasticsearch.ElasticSearchIllegalArgumentException;
import org.elasticsearch.common.thread.ThreadLocals;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.doubles.DoubleFieldData;
import org.elasticsearch.index.field.data.doubles.DoubleFieldDataComparator;
import org.elasticsearch.index.field.data.floats.FloatFieldData;
import org.elasticsearch.index.field.data.floats.FloatFieldDataComparator;
import org.elasticsearch.index.field.data.ints.IntFieldData;
import org.elasticsearch.index.field.data.ints.IntFieldDataComparator;
import org.elasticsearch.index.field.data.longs.LongFieldData;
import org.elasticsearch.index.field.data.longs.LongFieldDataComparator;
import org.elasticsearch.index.field.data.shorts.ShortFieldData;
import org.elasticsearch.index.field.data.shorts.ShortFieldDataComparator;
import org.elasticsearch.index.field.data.strings.StringFieldData;
import org.elasticsearch.index.field.data.strings.StringOrdValFieldDataComparator;
import java.io.IOException;
@ -39,25 +48,109 @@ import java.io.IOException;
public abstract class FieldData<Doc extends DocFieldData> {
public static enum Type {
STRING(StringFieldData.class, false),
SHORT(ShortFieldData.class, true),
INT(IntFieldData.class, true),
LONG(LongFieldData.class, true),
FLOAT(FloatFieldData.class, true),
DOUBLE(DoubleFieldData.class, true);
STRING() {
public final Class<? extends FieldData> fieldDataClass;
@Override public Class<? extends FieldData> fieldDataClass() {
return StringFieldData.class;
}
private final boolean isNumeric;
@Override public boolean isNumeric() {
return false;
}
Type(Class<? extends FieldData> clazz, boolean numeric) {
this.fieldDataClass = clazz;
this.isNumeric = numeric;
}
@Override public FieldComparatorSource newFieldComparatorSource(final FieldDataCache cache) {
return new FieldComparatorSource() {
@Override public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
return new StringOrdValFieldDataComparator(numHits, fieldname, sortPos, reversed, cache);
}
};
}},
SHORT() {
@Override public Class<? extends FieldData> fieldDataClass() {
return ShortFieldData.class;
}
public boolean isNumeric() {
return isNumeric;
}
@Override public boolean isNumeric() {
return true;
}
@Override public FieldComparatorSource newFieldComparatorSource(final FieldDataCache cache) {
return new FieldComparatorSource() {
@Override public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
return new ShortFieldDataComparator(numHits, fieldname, cache);
}
};
}},
INT() {
@Override public Class<? extends FieldData> fieldDataClass() {
return IntFieldData.class;
}
@Override public boolean isNumeric() {
return true;
}
@Override public FieldComparatorSource newFieldComparatorSource(final FieldDataCache cache) {
return new FieldComparatorSource() {
@Override public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
return new IntFieldDataComparator(numHits, fieldname, cache);
}
};
}},
LONG() {
@Override public Class<? extends FieldData> fieldDataClass() {
return LongFieldData.class;
}
@Override public boolean isNumeric() {
return true;
}
@Override public FieldComparatorSource newFieldComparatorSource(final FieldDataCache cache) {
return new FieldComparatorSource() {
@Override public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
return new LongFieldDataComparator(numHits, fieldname, cache);
}
};
}},
FLOAT() {
@Override public Class<? extends FieldData> fieldDataClass() {
return FloatFieldData.class;
}
@Override public boolean isNumeric() {
return true;
}
@Override public FieldComparatorSource newFieldComparatorSource(final FieldDataCache cache) {
return new FieldComparatorSource() {
@Override public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
return new FloatFieldDataComparator(numHits, fieldname, cache);
}
};
}},
DOUBLE() {
@Override public Class<? extends FieldData> fieldDataClass() {
return DoubleFieldData.class;
}
@Override public boolean isNumeric() {
return true;
}
@Override public FieldComparatorSource newFieldComparatorSource(final FieldDataCache cache) {
return new FieldComparatorSource() {
@Override public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
return new DoubleFieldDataComparator(numHits, fieldname, cache);
}
};
}};
public abstract Class<? extends FieldData> fieldDataClass();
public abstract boolean isNumeric();
public abstract FieldComparatorSource newFieldComparatorSource(FieldDataCache cache);
}
private final ThreadLocal<ThreadLocals.CleanableValue<Doc>> cachedDocFieldData = new ThreadLocal<ThreadLocals.CleanableValue<Doc>>() {
@ -116,8 +209,10 @@ public abstract class FieldData<Doc extends DocFieldData> {
*/
public abstract Type type();
public abstract FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed);
public static FieldData load(Type type, IndexReader reader, String fieldName) throws IOException {
return load(type.fieldDataClass, reader, fieldName);
return load(type.fieldDataClass(), reader, fieldName);
}
@SuppressWarnings({"unchecked"})

View File

@ -21,7 +21,9 @@ package org.elasticsearch.index.field.data.doubles;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.common.trove.TDoubleArrayList;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.field.data.support.FieldDataLoader;
@ -41,6 +43,10 @@ public abstract class DoubleFieldData extends NumericFieldData<DoubleDocFieldDat
this.values = values;
}
@Override public FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed) {
return new DoubleFieldDataComparator(numHits, field, fieldDataCache);
}
abstract public double value(int docId);
abstract public double[] values(int docId);

View File

@ -0,0 +1,77 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.doubles;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import org.elasticsearch.index.field.data.support.NumericFieldDataComparator;
/**
* @author kimchy (shay.banon)
*/
public class DoubleFieldDataComparator extends NumericFieldDataComparator {
private final double[] values;
private double bottom;
public DoubleFieldDataComparator(int numHits, String fieldName, FieldDataCache fieldDataCache) {
super(fieldName, fieldDataCache);
values = new double[numHits];
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.DOUBLE;
}
@Override public int compare(int slot1, int slot2) {
final double v1 = values[slot1];
final double v2 = values[slot2];
if (v1 > v2) {
return 1;
} else if (v1 < v2) {
return -1;
} else {
return 0;
}
}
@Override public int compareBottom(int doc) {
final double v2 = currentFieldData.doubleValue(doc);
if (bottom > v2) {
return 1;
} else if (bottom < v2) {
return -1;
} else {
return 0;
}
}
@Override public void copy(int slot, int doc) {
values[slot] = currentFieldData.doubleValue(doc);
}
@Override public void setBottom(final int bottom) {
this.bottom = values[bottom];
}
@Override public Comparable value(int slot) {
return Double.valueOf(values[slot]);
}
}

View File

@ -21,7 +21,9 @@ package org.elasticsearch.index.field.data.floats;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.common.trove.TFloatArrayList;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.field.data.support.FieldDataLoader;
@ -41,6 +43,10 @@ public abstract class FloatFieldData extends NumericFieldData<FloatDocFieldData>
this.values = values;
}
@Override public FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed) {
return new FloatFieldDataComparator(numHits, field, fieldDataCache);
}
abstract public float value(int docId);
abstract public float[] values(int docId);

View File

@ -0,0 +1,83 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.floats;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import org.elasticsearch.index.field.data.support.NumericFieldDataComparator;
/**
* @author kimchy (shay.banon)
*/
// LUCENE MONITOR - Monitor against FieldComparator.Float
public class FloatFieldDataComparator extends NumericFieldDataComparator {
private final float[] values;
private float bottom;
public FloatFieldDataComparator(int numHits, String fieldName, FieldDataCache fieldDataCache) {
super(fieldName, fieldDataCache);
values = new float[numHits];
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.FLOAT;
}
@Override public int compare(int slot1, int slot2) {
// TODO: are there sneaky non-branch ways to compute
// sign of float?
final float v1 = values[slot1];
final float v2 = values[slot2];
if (v1 > v2) {
return 1;
} else if (v1 < v2) {
return -1;
} else {
return 0;
}
}
@Override public int compareBottom(int doc) {
// TODO: are there sneaky non-branch ways to compute
// sign of float?
final float v2 = currentFieldData.floatValue(doc);
if (bottom > v2) {
return 1;
} else if (bottom < v2) {
return -1;
} else {
return 0;
}
}
@Override
public void copy(int slot, int doc) {
values[slot] = currentFieldData.floatValue(doc);
}
@Override public void setBottom(final int bottom) {
this.bottom = values[bottom];
}
@Override public Comparable value(int slot) {
return Float.valueOf(values[slot]);
}
}

View File

@ -21,7 +21,9 @@ package org.elasticsearch.index.field.data.ints;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.common.trove.TIntArrayList;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.field.data.support.FieldDataLoader;
@ -41,6 +43,10 @@ public abstract class IntFieldData extends NumericFieldData<IntDocFieldData> {
this.values = values;
}
@Override public FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed) {
return new IntFieldDataComparator(numHits, field, fieldDataCache);
}
abstract public int value(int docId);
abstract public int[] values(int docId);

View File

@ -0,0 +1,88 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.ints;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import org.elasticsearch.index.field.data.support.NumericFieldDataComparator;
/**
* @author kimchy (shay.banon)
*/
// LUCENE MONITOR - Monitor against FieldComparator.Int
public class IntFieldDataComparator extends NumericFieldDataComparator {
private final int[] values;
private int bottom; // Value of bottom of queue
public IntFieldDataComparator(int numHits, String fieldName, FieldDataCache fieldDataCache) {
super(fieldName, fieldDataCache);
values = new int[numHits];
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.INT;
}
@Override public int compare(int slot1, int slot2) {
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
// Cannot return values[slot1] - values[slot2] because that
// may overflow
final int v1 = values[slot1];
final int v2 = values[slot2];
if (v1 > v2) {
return 1;
} else if (v1 < v2) {
return -1;
} else {
return 0;
}
}
@Override public int compareBottom(int doc) {
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
// Cannot return bottom - values[slot2] because that
// may overflow
// final int v2 = currentReaderValues[doc];
final int v2 = currentFieldData.intValue(doc);
if (bottom > v2) {
return 1;
} else if (bottom < v2) {
return -1;
} else {
return 0;
}
}
@Override public void copy(int slot, int doc) {
values[slot] = currentFieldData.intValue(doc);
}
@Override public void setBottom(final int bottom) {
this.bottom = values[bottom];
}
@Override public Comparable value(int slot) {
return Integer.valueOf(values[slot]);
}
}

View File

@ -21,9 +21,11 @@ package org.elasticsearch.index.field.data.longs;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.common.joda.time.MutableDateTime;
import org.elasticsearch.common.thread.ThreadLocals;
import org.elasticsearch.common.trove.TLongArrayList;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.field.data.support.FieldDataLoader;
@ -50,6 +52,10 @@ public abstract class LongFieldData extends NumericFieldData<LongDocFieldData> {
this.values = values;
}
@Override public FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed) {
return new LongFieldDataComparator(numHits, field, fieldDataCache);
}
abstract public long value(int docId);
abstract public long[] values(int docId);

View File

@ -0,0 +1,86 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.longs;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import org.elasticsearch.index.field.data.support.NumericFieldDataComparator;
/**
* @author kimchy (shay.banon)
*/
// LUCENE MONITOR - Monitor against FieldComparator.Long
public class LongFieldDataComparator extends NumericFieldDataComparator {
private final long[] values;
private long bottom;
public LongFieldDataComparator(int numHits, String fieldName, FieldDataCache fieldDataCache) {
super(fieldName, fieldDataCache);
values = new long[numHits];
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.LONG;
}
@Override public int compare(int slot1, int slot2) {
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
final long v1 = values[slot1];
final long v2 = values[slot2];
if (v1 > v2) {
return 1;
} else if (v1 < v2) {
return -1;
} else {
return 0;
}
}
@Override
public int compareBottom(int doc) {
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
// final long v2 = currentReaderValues[doc];
final long v2 = currentFieldData.longValue(doc);
if (bottom > v2) {
return 1;
} else if (bottom < v2) {
return -1;
} else {
return 0;
}
}
@Override
public void copy(int slot, int doc) {
values[slot] = currentFieldData.longValue(doc);
}
@Override public void setBottom(final int bottom) {
this.bottom = values[bottom];
}
@Override public Comparable value(int slot) {
return Long.valueOf(values[slot]);
}
}

View File

@ -21,7 +21,9 @@ package org.elasticsearch.index.field.data.shorts;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.common.trove.TShortArrayList;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.NumericFieldData;
import org.elasticsearch.index.field.data.support.FieldDataLoader;
@ -41,6 +43,10 @@ public abstract class ShortFieldData extends NumericFieldData<ShortDocFieldData>
this.values = values;
}
@Override public FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed) {
return new ShortFieldDataComparator(numHits, field, fieldDataCache);
}
abstract public short value(int docId);
abstract public short[] values(int docId);

View File

@ -0,0 +1,62 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.shorts;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import org.elasticsearch.index.field.data.support.NumericFieldDataComparator;
/**
* @author kimchy (shay.banon)
*/
public class ShortFieldDataComparator extends NumericFieldDataComparator {
private final short[] values;
private short bottom;
public ShortFieldDataComparator(int numHits, String fieldName, FieldDataCache fieldDataCache) {
super(fieldName, fieldDataCache);
values = new short[numHits];
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.SHORT;
}
@Override public int compare(int slot1, int slot2) {
return values[slot1] - values[slot2];
}
@Override public int compareBottom(int doc) {
return bottom - currentFieldData.shortValue(doc);
}
@Override public void copy(int slot, int doc) {
values[slot] = currentFieldData.shortValue(doc);
}
@Override public void setBottom(final int bottom) {
this.bottom = values[bottom];
}
@Override public Comparable value(int slot) {
return Short.valueOf(values[slot]);
}
}

View File

@ -19,8 +19,10 @@
package org.elasticsearch.index.field.data.strings;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.thread.ThreadLocals;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
/**
* @author kimchy (shay.banon)
@ -47,6 +49,10 @@ public class MultiValueStringFieldData extends StringFieldData {
this.order = order;
}
@Override public FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed) {
return new StringValFieldDataComparator(numHits, field, fieldDataCache);
}
@Override public boolean multiValued() {
return true;
}

View File

@ -19,8 +19,10 @@
package org.elasticsearch.index.field.data.strings;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.thread.ThreadLocals;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
/**
* @author kimchy (shay.banon)
@ -41,6 +43,18 @@ public class SingleValueStringFieldData extends StringFieldData {
this.order = order;
}
@Override public FieldComparator newComparator(FieldDataCache fieldDataCache, int numHits, String field, int sortPos, boolean reversed) {
return new StringOrdValFieldDataComparator(numHits, field, sortPos, reversed, fieldDataCache);
}
int[] order() {
return order;
}
String[] values() {
return this.values;
}
@Override public boolean multiValued() {
return false;
}

View File

@ -0,0 +1,180 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.strings;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import java.io.IOException;
/**
* @author kimchy (shay.banon)
*/
public class StringOrdValFieldDataComparator extends FieldComparator {
private final FieldDataCache fieldDataCache;
private final int[] ords;
private final String[] values;
private final int[] readerGen;
private int currentReaderGen = -1;
private String[] lookup;
private int[] order;
private final String field;
private int bottomSlot = -1;
private int bottomOrd;
private String bottomValue;
private final boolean reversed;
private final int sortPos;
public StringOrdValFieldDataComparator(int numHits, String field, int sortPos, boolean reversed, FieldDataCache fieldDataCache) {
this.fieldDataCache = fieldDataCache;
ords = new int[numHits];
values = new String[numHits];
readerGen = new int[numHits];
this.sortPos = sortPos;
this.reversed = reversed;
this.field = field;
}
@Override public int compare(int slot1, int slot2) {
if (readerGen[slot1] == readerGen[slot2]) {
int cmp = ords[slot1] - ords[slot2];
if (cmp != 0) {
return cmp;
}
}
final String val1 = values[slot1];
final String val2 = values[slot2];
if (val1 == null) {
if (val2 == null) {
return 0;
}
return -1;
} else if (val2 == null) {
return 1;
}
return val1.compareTo(val2);
}
@Override public int compareBottom(int doc) {
assert bottomSlot != -1;
int order = this.order[doc];
final int cmp = bottomOrd - order;
if (cmp != 0) {
return cmp;
}
final String val2 = lookup[order];
if (bottomValue == null) {
if (val2 == null) {
return 0;
}
// bottom wins
return -1;
} else if (val2 == null) {
// doc wins
return 1;
}
return bottomValue.compareTo(val2);
}
private void convert(int slot) {
readerGen[slot] = currentReaderGen;
int index = 0;
String value = values[slot];
if (value == null) {
ords[slot] = 0;
return;
}
if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
// Since we are the primary sort, the entries in the
// queue are bounded by bottomOrd:
assert bottomOrd < lookup.length;
if (reversed) {
index = binarySearch(lookup, value, bottomOrd, lookup.length - 1);
} else {
index = binarySearch(lookup, value, 0, bottomOrd);
}
} else {
// Full binary search
index = binarySearch(lookup, value);
}
if (index < 0) {
index = -index - 2;
}
ords[slot] = index;
}
@Override public void copy(int slot, int doc) {
final int ord = order[doc];
ords[slot] = ord;
assert ord >= 0;
values[slot] = lookup[ord];
readerGen[slot] = currentReaderGen;
}
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
SingleValueStringFieldData fieldData = (SingleValueStringFieldData) fieldDataCache.cache(FieldData.Type.STRING, reader, field);
currentReaderGen++;
order = fieldData.order();
lookup = fieldData.values();
assert lookup.length > 0;
if (bottomSlot != -1) {
convert(bottomSlot);
bottomOrd = ords[bottomSlot];
}
}
@Override public void setBottom(final int bottom) {
bottomSlot = bottom;
if (readerGen[bottom] != currentReaderGen) {
convert(bottomSlot);
}
bottomOrd = ords[bottom];
assert bottomOrd >= 0;
assert bottomOrd < lookup.length;
bottomValue = values[bottom];
}
@Override public Comparable value(int slot) {
return values[slot];
}
public String[] getValues() {
return values;
}
public int getBottomSlot() {
return bottomSlot;
}
public String getField() {
return field;
}
}

View File

@ -0,0 +1,93 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.strings;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import java.io.IOException;
/**
* @author kimchy (shay.banon)
*/
public class StringValFieldDataComparator extends FieldComparator {
private final String fieldName;
protected final FieldDataCache fieldDataCache;
protected FieldData currentFieldData;
private String[] values;
private String bottom;
public StringValFieldDataComparator(int numHits, String fieldName, FieldDataCache fieldDataCache) {
this.fieldName = fieldName;
this.fieldDataCache = fieldDataCache;
values = new String[numHits];
}
@Override public int compare(int slot1, int slot2) {
final String val1 = values[slot1];
final String val2 = values[slot2];
if (val1 == null) {
if (val2 == null) {
return 0;
}
return -1;
} else if (val2 == null) {
return 1;
}
return val1.compareTo(val2);
}
@Override public int compareBottom(int doc) {
final String val2 = currentFieldData.stringValue(doc);
if (bottom == null) {
if (val2 == null) {
return 0;
}
return -1;
} else if (val2 == null) {
return 1;
}
return bottom.compareTo(val2);
}
@Override public void copy(int slot, int doc) {
values[slot] = currentFieldData.stringValue(doc);
}
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
currentFieldData = fieldDataCache.cache(FieldData.Type.STRING, reader, fieldName);
}
@Override public void setBottom(final int bottom) {
this.bottom = values[bottom];
}
@Override public Comparable value(int slot) {
return values[slot];
}
}

View File

@ -0,0 +1,51 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search 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.elasticsearch.index.field.data.support;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.FieldComparator;
import org.elasticsearch.index.cache.field.data.FieldDataCache;
import org.elasticsearch.index.field.data.FieldData;
import org.elasticsearch.index.field.data.NumericFieldData;
import java.io.IOException;
/**
* @author kimchy (shay.banon)
*/
public abstract class NumericFieldDataComparator extends FieldComparator {
private final String fieldName;
protected final FieldDataCache fieldDataCache;
protected NumericFieldData currentFieldData;
public NumericFieldDataComparator(String fieldName, FieldDataCache fieldDataCache) {
this.fieldName = fieldName;
this.fieldDataCache = fieldDataCache;
}
public abstract FieldData.Type fieldDataType();
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
currentFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType(), reader, fieldName);
}
}

View File

@ -167,7 +167,5 @@ public interface FieldMapper<T> {
*/
Filter rangeFilter(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper);
int sortType();
FieldData.Type fieldDataType();
}

View File

@ -21,7 +21,10 @@ package org.elasticsearch.index.mapper.xcontent;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.xcontent.XContentParser;
@ -169,10 +172,6 @@ public class XContentBoostFieldMapper extends XContentNumberFieldMapper<Float> i
return value;
}
@Override public int sortType() {
return SortField.FLOAT;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.FLOAT;
}

View File

@ -21,7 +21,10 @@ package org.elasticsearch.index.mapper.xcontent;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.Strings;
@ -202,10 +205,6 @@ public class XContentDateFieldMapper extends XContentNumberFieldMapper<Long> {
return field;
}
@Override public int sortType() {
return SortField.LONG;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.LONG;
}

View File

@ -21,7 +21,10 @@ package org.elasticsearch.index.mapper.xcontent;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.xcontent.XContentParser;
@ -184,10 +187,6 @@ public class XContentDoubleFieldMapper extends XContentNumberFieldMapper<Double>
return field;
}
@Override public int sortType() {
return SortField.DOUBLE;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.DOUBLE;
}

View File

@ -344,10 +344,6 @@ public abstract class XContentFieldMapper<T> implements FieldMapper<T>, XContent
mergeContext.addConflict("Mapper [" + names.fullName() + "] exists, can't merge");
}
@Override public int sortType() {
return SortField.STRING;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.STRING;
}

View File

@ -21,7 +21,10 @@ package org.elasticsearch.index.mapper.xcontent;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.Strings;
@ -183,10 +186,6 @@ public class XContentFloatFieldMapper extends XContentNumberFieldMapper<Float> {
return field;
}
@Override public int sortType() {
return SortField.FLOAT;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.FLOAT;
}

View File

@ -21,7 +21,10 @@ package org.elasticsearch.index.mapper.xcontent;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.Strings;
@ -183,10 +186,6 @@ public class XContentIntegerFieldMapper extends XContentNumberFieldMapper<Intege
return field;
}
@Override public int sortType() {
return SortField.INT;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.INT;
}

View File

@ -21,7 +21,10 @@ package org.elasticsearch.index.mapper.xcontent;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.Strings;
@ -183,10 +186,6 @@ public class XContentLongFieldMapper extends XContentNumberFieldMapper<Long> {
return field;
}
@Override public int sortType() {
return SortField.LONG;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.LONG;
}

View File

@ -161,8 +161,6 @@ public abstract class XContentNumberFieldMapper<T extends Number> extends XConte
builder.field("precision_step", precisionStep);
}
@Override public abstract int sortType();
@Override public abstract FieldData.Type fieldDataType();
/**

View File

@ -21,7 +21,10 @@ package org.elasticsearch.index.mapper.xcontent;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.search.*;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.common.Numbers;
import org.elasticsearch.common.Strings;
@ -183,10 +186,6 @@ public class XContentShortFieldMapper extends XContentNumberFieldMapper<Short> {
return field;
}
@Override public int sortType() {
return SortField.SHORT;
}
@Override public FieldData.Type fieldDataType() {
return FieldData.Type.SHORT;
}

View File

@ -156,17 +156,7 @@ public class SearchSourceBuilder implements ToXContent {
reverse = true;
}
}
return sort(name, null, reverse);
}
/**
* Add a sort against the given field name and if it should be revered or not.
*
* @param name The name of the field to sort by
* @param reverse Should be soring be reversed or not
*/
public SearchSourceBuilder sort(String name, boolean reverse) {
return sort(name, null, reverse);
return sort(name, reverse);
}
/**
@ -175,31 +165,20 @@ public class SearchSourceBuilder implements ToXContent {
* @param name The name of the field to sort by
*/
public SearchSourceBuilder sort(String name) {
return sort(name, null, false);
}
/**
* Add a sort against the given field name of the given type.
*
* @param name The name of the field to sort by
* @param type The type of sort to perform
*/
public SearchSourceBuilder sort(String name, String type) {
return sort(name, type, false);
return sort(name, false);
}
/**
* Add a sort against the given field name and if it should be revered or not.
*
* @param name The name of the field to sort by
* @param type The type of the sort to perform
* @param reverse Should the sort be reversed or not
*/
public SearchSourceBuilder sort(String name, String type, boolean reverse) {
public SearchSourceBuilder sort(String name, boolean reverse) {
if (sortFields == null) {
sortFields = newArrayListWithCapacity(2);
}
sortFields.add(new SortTuple(name, reverse, type));
sortFields.add(new SortTuple(name, reverse));
return this;
}
@ -366,12 +345,9 @@ public class SearchSourceBuilder implements ToXContent {
for (SortTuple sortTuple : sortFields) {
builder.field(sortTuple.fieldName());
builder.startObject();
if (sortTuple.reverse) {
if (sortTuple.reverse()) {
builder.field("reverse", true);
}
if (sortTuple.type != null) {
builder.field("type", sortTuple.type());
}
builder.endObject();
}
builder.endObject();
@ -429,12 +405,10 @@ public class SearchSourceBuilder implements ToXContent {
private static class SortTuple {
private final String fieldName;
private final boolean reverse;
private final String type;
private SortTuple(String fieldName, boolean reverse, String type) {
private SortTuple(String fieldName, boolean reverse) {
this.fieldName = fieldName;
this.reverse = reverse;
this.type = type;
}
public String fieldName() {
@ -444,9 +418,5 @@ public class SearchSourceBuilder implements ToXContent {
public boolean reverse() {
return reverse;
}
public String type() {
return type;
}
}
}

View File

@ -99,7 +99,22 @@ public class QueryPhase implements SearchPhase {
// if 0 was asked, change it to 1 since 0 is not allowed
numDocs = 1;
}
boolean sort = false;
// try and optimize for a case where the sorting is based on score, this is how we work by default!
if (searchContext.sort() != null) {
if (searchContext.sort().getSort().length > 0) {
sort = true;
} else {
SortField sortField = searchContext.sort().getSort()[0];
if (sortField.getType() == SortField.SCORE && !sortField.getReverse()) {
sort = false;
} else {
sort = true;
}
}
}
if (sort) {
topDocs = searchContext.searcher().search(query, null, numDocs, searchContext.sort());
} else {
topDocs = searchContext.searcher().search(query, numDocs);

View File

@ -21,12 +21,9 @@ package org.elasticsearch.search.query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.trove.ExtTObjectIntHasMap;
import org.elasticsearch.common.trove.TObjectIntHashMap;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.FieldMappers;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.internal.SearchContext;
@ -39,22 +36,12 @@ import java.util.List;
*/
public class SortParseElement implements SearchParseElement {
private final TObjectIntHashMap<String> sortFieldTypesMapper = new ExtTObjectIntHasMap<String>().defaultReturnValue(-1);
private static final SortField SORT_SCORE = new SortField(null, SortField.SCORE);
private static final SortField SORT_SCORE_REVERSE = new SortField(null, SortField.SCORE, true);
private static final SortField SORT_DOC = new SortField(null, SortField.DOC);
private static final SortField SORT_DOC_REVERSE = new SortField(null, SortField.DOC, true);
public SortParseElement() {
sortFieldTypesMapper.put("string", SortField.STRING);
sortFieldTypesMapper.put("int", SortField.INT);
sortFieldTypesMapper.put("float", SortField.FLOAT);
sortFieldTypesMapper.put("long", SortField.LONG);
sortFieldTypesMapper.put("double", SortField.DOUBLE);
sortFieldTypesMapper.put("short", SortField.SHORT);
sortFieldTypesMapper.put("byte", SortField.BYTE);
sortFieldTypesMapper.put("string_val", SortField.STRING_VAL);
}
@Override public void parse(XContentParser parser, SearchContext context) throws Exception {
@ -65,7 +52,7 @@ public class SortParseElement implements SearchParseElement {
if (token == XContentParser.Token.START_OBJECT) {
addCompoundSortField(parser, context, sortFields);
} else if (token == XContentParser.Token.VALUE_STRING) {
addSortField(context, sortFields, parser.text(), false, -1);
addSortField(context, sortFields, parser.text(), false);
}
}
} else {
@ -83,36 +70,18 @@ public class SortParseElement implements SearchParseElement {
String fieldName = parser.currentName();
boolean reverse = false;
String innerJsonName = null;
int type = -1;
token = parser.nextToken();
if (token == XContentParser.Token.VALUE_STRING) {
String direction = parser.text();
if (direction.equals("asc")) {
if ("score".equals(fieldName)) {
reverse = true;
} else {
reverse = false;
}
reverse = "score".equals(fieldName);
} else if (direction.equals("desc")) {
if ("score".equals(fieldName)) {
reverse = false;
} else {
reverse = true;
}
reverse = !"score".equals(fieldName);
}
} else {
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
innerJsonName = parser.currentName();
} else if (token == XContentParser.Token.VALUE_STRING) {
if ("type".equals(innerJsonName)) {
type = sortFieldTypesMapper.get(parser.text());
if (type == -1) {
throw new SearchParseException(context, "No sort type for [" + parser.text() + "] with field [" + fieldName + "]");
}
} else if ("reverse".equals(innerJsonName)) {
reverse = Booleans.parseBoolean(parser.text(), reverse);
}
} else if (token.isValue()) {
if ("reverse".equals(innerJsonName)) {
reverse = parser.booleanValue();
@ -120,12 +89,12 @@ public class SortParseElement implements SearchParseElement {
}
}
}
addSortField(context, sortFields, fieldName, reverse, type);
addSortField(context, sortFields, fieldName, reverse);
}
}
}
private void addSortField(SearchContext context, List<SortField> sortFields, String fieldName, boolean reverse, int type) {
private void addSortField(SearchContext context, List<SortField> sortFields, String fieldName, boolean reverse) {
if ("score".equals(fieldName)) {
if (reverse) {
sortFields.add(SORT_SCORE_REVERSE);
@ -139,18 +108,11 @@ public class SortParseElement implements SearchParseElement {
sortFields.add(SORT_DOC);
}
} else {
FieldMappers fieldMappers = context.mapperService().smartNameFieldMappers(fieldName);
if (fieldMappers == null || fieldMappers.mappers().isEmpty()) {
if (type == -1) {
throw new SearchParseException(context, "No built in mapping found for [" + fieldName + "], and no explicit type defined");
}
} else {
fieldName = fieldMappers.mappers().get(0).names().indexName();
if (type == -1) {
type = fieldMappers.mappers().get(0).sortType();
}
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(fieldName);
if (fieldMapper == null) {
throw new SearchParseException(context, "No mapping found for [" + fieldName + "]");
}
sortFields.add(new SortField(fieldName, type, reverse));
sortFields.add(new SortField(fieldName, fieldMapper.fieldDataType().newFieldComparatorSource(context.fieldDataCache()), reverse));
}
}
}

View File

@ -67,7 +67,7 @@ import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
/**
* @author kimchy (Shay Banon)
* @author kimchy (shay.banon)
*/
public class TwoInstanceEmbeddedSearchTests extends AbstractNodesTests {