|
@@ -25,32 +25,62 @@ import org.apache.lucene.util.BytesRef;
|
|
|
import org.elasticsearch.common.geo.GeoHashUtils;
|
|
|
import org.elasticsearch.common.geo.GeoPoint;
|
|
|
import org.elasticsearch.common.geo.GeoUtils;
|
|
|
+import org.joda.time.DateTime;
|
|
|
import org.joda.time.DateTimeZone;
|
|
|
import org.joda.time.MutableDateTime;
|
|
|
import org.joda.time.ReadableDateTime;
|
|
|
|
|
|
import java.util.AbstractList;
|
|
|
-import java.util.Collections;
|
|
|
+import java.util.Comparator;
|
|
|
import java.util.List;
|
|
|
+import java.util.function.UnaryOperator;
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Script level doc values, the assumption is that any implementation will implement a <code>getValue</code>
|
|
|
* and a <code>getValues</code> that return the relevant type that then can be used in scripts.
|
|
|
*/
|
|
|
-public interface ScriptDocValues<T> extends List<T> {
|
|
|
+public abstract class ScriptDocValues<T> extends AbstractList<T> {
|
|
|
|
|
|
/**
|
|
|
* Set the current doc ID.
|
|
|
*/
|
|
|
- void setNextDocId(int docId);
|
|
|
+ public abstract void setNextDocId(int docId);
|
|
|
|
|
|
/**
|
|
|
* Return a copy of the list of the values for the current document.
|
|
|
*/
|
|
|
- List<T> getValues();
|
|
|
+ public final List<T> getValues() {
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Throw meaningful exceptions if someone tries to modify the ScriptDocValues.
|
|
|
+ @Override
|
|
|
+ public final void add(int index, T element) {
|
|
|
+ throw new UnsupportedOperationException("doc values are unmodifiable");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final boolean remove(Object o) {
|
|
|
+ throw new UnsupportedOperationException("doc values are unmodifiable");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final void replaceAll(UnaryOperator<T> operator) {
|
|
|
+ throw new UnsupportedOperationException("doc values are unmodifiable");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final T set(int index, T element) {
|
|
|
+ throw new UnsupportedOperationException("doc values are unmodifiable");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final void sort(Comparator<? super T> c) {
|
|
|
+ throw new UnsupportedOperationException("doc values are unmodifiable");
|
|
|
+ }
|
|
|
|
|
|
- public static final class Strings extends AbstractList<String> implements ScriptDocValues<String> {
|
|
|
+ public static final class Strings extends ScriptDocValues<String> {
|
|
|
|
|
|
private final SortedBinaryDocValues values;
|
|
|
|
|
@@ -84,11 +114,6 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public List<String> getValues() {
|
|
|
- return Collections.unmodifiableList(this);
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public String get(int index) {
|
|
|
return values.valueAt(index).utf8ToString();
|
|
@@ -101,10 +126,10 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
|
|
|
}
|
|
|
|
|
|
- public static class Longs extends AbstractList<Long> implements ScriptDocValues<Long> {
|
|
|
+ public static final class Longs extends ScriptDocValues<Long> {
|
|
|
|
|
|
private final SortedNumericDocValues values;
|
|
|
- private final MutableDateTime date = new MutableDateTime(0, DateTimeZone.UTC);
|
|
|
+ private Dates dates;
|
|
|
|
|
|
public Longs(SortedNumericDocValues values) {
|
|
|
this.values = values;
|
|
@@ -113,6 +138,9 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
@Override
|
|
|
public void setNextDocId(int docId) {
|
|
|
values.setDocument(docId);
|
|
|
+ if (dates != null) {
|
|
|
+ dates.refreshArray();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public SortedNumericDocValues getInternalValues() {
|
|
@@ -127,14 +155,20 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
return values.valueAt(0);
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public List<Long> getValues() {
|
|
|
- return Collections.unmodifiableList(this);
|
|
|
+ public ReadableDateTime getDate() {
|
|
|
+ if (dates == null) {
|
|
|
+ dates = new Dates(values);
|
|
|
+ dates.refreshArray();
|
|
|
+ }
|
|
|
+ return dates.getValue();
|
|
|
}
|
|
|
|
|
|
- public ReadableDateTime getDate() {
|
|
|
- date.setMillis(getValue());
|
|
|
- return date;
|
|
|
+ public List<ReadableDateTime> getDates() {
|
|
|
+ if (dates == null) {
|
|
|
+ dates = new Dates(values);
|
|
|
+ dates.refreshArray();
|
|
|
+ }
|
|
|
+ return dates;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -146,10 +180,87 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
public int size() {
|
|
|
return values.count();
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ public static final class Dates extends ScriptDocValues<ReadableDateTime> {
|
|
|
+ private static final ReadableDateTime EPOCH = new DateTime(0, DateTimeZone.UTC);
|
|
|
+
|
|
|
+ private final SortedNumericDocValues values;
|
|
|
+ /**
|
|
|
+ * Values wrapped in {@link MutableDateTime}. Null by default an allocated on first usage so we allocate a reasonably size. We keep
|
|
|
+ * this array so we don't have allocate new {@link MutableDateTime}s on every usage. Instead we reuse them for every document.
|
|
|
+ */
|
|
|
+ private MutableDateTime[] dates;
|
|
|
+
|
|
|
+ public Dates(SortedNumericDocValues values) {
|
|
|
+ this.values = values;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Fetch the first field value or 0 millis after epoch if there are no values.
|
|
|
+ */
|
|
|
+ public ReadableDateTime getValue() {
|
|
|
+ if (values.count() == 0) {
|
|
|
+ return EPOCH;
|
|
|
+ }
|
|
|
+ return get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ReadableDateTime get(int index) {
|
|
|
+ if (index >= values.count()) {
|
|
|
+ throw new IndexOutOfBoundsException(
|
|
|
+ "attempted to fetch the [" + index + "] date when there are only [" + values.count() + "] dates.");
|
|
|
+ }
|
|
|
+ return dates[index];
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int size() {
|
|
|
+ return values.count();
|
|
|
+ }
|
|
|
|
|
|
+ @Override
|
|
|
+ public void setNextDocId(int docId) {
|
|
|
+ values.setDocument(docId);
|
|
|
+ refreshArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Refresh the backing array. Package private so it can be called when {@link Longs} loads dates.
|
|
|
+ */
|
|
|
+ void refreshArray() {
|
|
|
+ if (values.count() == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (dates == null) {
|
|
|
+ // Happens for the document. We delay allocating dates so we can allocate it with a reasonable size.
|
|
|
+ dates = new MutableDateTime[values.count()];
|
|
|
+ for (int i = 0; i < dates.length; i++) {
|
|
|
+ dates[i] = new MutableDateTime(values.valueAt(i), DateTimeZone.UTC);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (values.count() > dates.length) {
|
|
|
+ // Happens when we move to a new document and it has more dates than any documents before it.
|
|
|
+ MutableDateTime[] backup = dates;
|
|
|
+ dates = new MutableDateTime[values.count()];
|
|
|
+ System.arraycopy(backup, 0, dates, 0, backup.length);
|
|
|
+ for (int i = 0; i < backup.length; i++) {
|
|
|
+ dates[i].setMillis(values.valueAt(i));
|
|
|
+ }
|
|
|
+ for (int i = backup.length; i < dates.length; i++) {
|
|
|
+ dates[i] = new MutableDateTime(values.valueAt(i), DateTimeZone.UTC);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ for (int i = 0; i < values.count(); i++) {
|
|
|
+ dates[i].setMillis(values.valueAt(i));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public static class Doubles extends AbstractList<Double> implements ScriptDocValues<Double> {
|
|
|
+ public static final class Doubles extends ScriptDocValues<Double> {
|
|
|
|
|
|
private final SortedNumericDoubleValues values;
|
|
|
|
|
@@ -174,11 +285,6 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
return values.valueAt(0);
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public List<Double> getValues() {
|
|
|
- return Collections.unmodifiableList(this);
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public Double get(int index) {
|
|
|
return values.valueAt(index);
|
|
@@ -190,7 +296,7 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- class GeoPoints extends AbstractList<GeoPoint> implements ScriptDocValues<GeoPoint> {
|
|
|
+ public static final class GeoPoints extends ScriptDocValues<GeoPoint> {
|
|
|
|
|
|
private final MultiGeoPointValues values;
|
|
|
|
|
@@ -237,11 +343,6 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
return getValue().lon();
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public List<GeoPoint> getValues() {
|
|
|
- return Collections.unmodifiableList(this);
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public GeoPoint get(int index) {
|
|
|
final GeoPoint point = values.valueAt(index);
|
|
@@ -291,7 +392,7 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- final class Booleans extends AbstractList<Boolean> implements ScriptDocValues<Boolean> {
|
|
|
+ public static final class Booleans extends ScriptDocValues<Boolean> {
|
|
|
|
|
|
private final SortedNumericDocValues values;
|
|
|
|
|
@@ -304,11 +405,6 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
values.setDocument(docId);
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public List<Boolean> getValues() {
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
public boolean getValue() {
|
|
|
return values.count() != 0 && values.valueAt(0) == 1;
|
|
|
}
|
|
@@ -325,7 +421,7 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
|
|
|
}
|
|
|
|
|
|
- public static class BytesRefs extends AbstractList<BytesRef> implements ScriptDocValues<BytesRef> {
|
|
|
+ public static final class BytesRefs extends ScriptDocValues<BytesRef> {
|
|
|
|
|
|
private final SortedBinaryDocValues values;
|
|
|
|
|
@@ -350,11 +446,6 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
return values.valueAt(0);
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public List<BytesRef> getValues() {
|
|
|
- return Collections.unmodifiableList(this);
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public BytesRef get(int index) {
|
|
|
return values.valueAt(index);
|
|
@@ -365,5 +456,4 @@ public interface ScriptDocValues<T> extends List<T> {
|
|
|
return values.count();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|