|
@@ -37,20 +37,19 @@ import org.elasticsearch.index.mapper.MappedFieldType;
|
|
|
import org.elasticsearch.index.mapper.MapperService;
|
|
|
import org.elasticsearch.index.mapper.core.DateFieldMapper;
|
|
|
import org.elasticsearch.index.mapper.core.LegacyDateFieldMapper;
|
|
|
+import org.elasticsearch.index.mapper.geo.BaseGeoPointFieldMapper;
|
|
|
import org.elasticsearch.script.ClassPermission;
|
|
|
import org.elasticsearch.script.CompiledScript;
|
|
|
import org.elasticsearch.script.ExecutableScript;
|
|
|
import org.elasticsearch.script.ScriptEngineService;
|
|
|
import org.elasticsearch.script.ScriptException;
|
|
|
import org.elasticsearch.script.SearchScript;
|
|
|
-import org.elasticsearch.search.MultiValueMode;
|
|
|
import org.elasticsearch.search.lookup.SearchLookup;
|
|
|
|
|
|
import java.security.AccessControlContext;
|
|
|
import java.security.AccessController;
|
|
|
import java.security.PrivilegedAction;
|
|
|
import java.text.ParseException;
|
|
|
-import java.util.Calendar;
|
|
|
import java.util.Collections;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
@@ -65,26 +64,6 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
|
|
|
|
|
|
public static final List<String> TYPES = Collections.singletonList(NAME);
|
|
|
|
|
|
- // these methods only work on dates, e.g. doc['datefield'].getYear()
|
|
|
- protected static final String GET_YEAR_METHOD = "getYear";
|
|
|
- protected static final String GET_MONTH_METHOD = "getMonth";
|
|
|
- protected static final String GET_DAY_OF_MONTH_METHOD = "getDayOfMonth";
|
|
|
- protected static final String GET_HOUR_OF_DAY_METHOD = "getHourOfDay";
|
|
|
- protected static final String GET_MINUTES_METHOD = "getMinutes";
|
|
|
- protected static final String GET_SECONDS_METHOD = "getSeconds";
|
|
|
-
|
|
|
- // these methods work on any field, e.g. doc['field'].sum()
|
|
|
- protected static final String MINIMUM_METHOD = "min";
|
|
|
- protected static final String MAXIMUM_METHOD = "max";
|
|
|
- protected static final String AVERAGE_METHOD = "avg";
|
|
|
- protected static final String MEDIAN_METHOD = "median";
|
|
|
- protected static final String SUM_METHOD = "sum";
|
|
|
- protected static final String COUNT_METHOD = "count";
|
|
|
-
|
|
|
- // these variables work on any field, e.g. doc['field'].value
|
|
|
- protected static final String VALUE_VARIABLE = "value";
|
|
|
- protected static final String EMPTY_VARIABLE = "empty";
|
|
|
-
|
|
|
@Inject
|
|
|
public ExpressionScriptEngineService(Settings settings) {
|
|
|
super(settings);
|
|
@@ -175,7 +154,7 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
|
|
|
} else {
|
|
|
String fieldname = null;
|
|
|
String methodname = null;
|
|
|
- String variablename = VALUE_VARIABLE; // .value is the default for doc['field'], its optional.
|
|
|
+ String variablename = "value"; // .value is the default for doc['field'], its optional.
|
|
|
VariableContext[] parts = VariableContext.parse(variable);
|
|
|
if (parts[0].text.equals("doc") == false) {
|
|
|
throw new ScriptException("Unknown variable [" + parts[0].text + "] in expression");
|
|
@@ -205,15 +184,38 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
|
|
|
}
|
|
|
|
|
|
IndexFieldData<?> fieldData = lookup.doc().fieldDataService().getForField(fieldType);
|
|
|
- if (fieldData instanceof IndexNumericFieldData == false) {
|
|
|
- // TODO: more context (which expression?)
|
|
|
- throw new ScriptException("Field [" + fieldname + "] used in expression must be numeric");
|
|
|
- }
|
|
|
- if (methodname == null) {
|
|
|
- bindings.add(variable, getVariableValueSource(fieldType, fieldData, fieldname, variablename));
|
|
|
+
|
|
|
+ // delegate valuesource creation based on field's type
|
|
|
+ // there are three types of "fields" to expressions, and each one has a different "api" of variables and methods.
|
|
|
+
|
|
|
+ final ValueSource valueSource;
|
|
|
+ if (fieldType instanceof BaseGeoPointFieldMapper.GeoPointFieldType) {
|
|
|
+ // geo
|
|
|
+ if (methodname == null) {
|
|
|
+ valueSource = GeoField.getVariable(fieldData, fieldname, variablename);
|
|
|
+ } else {
|
|
|
+ valueSource = GeoField.getMethod(fieldData, fieldname, methodname);
|
|
|
+ }
|
|
|
+ } else if (fieldType instanceof LegacyDateFieldMapper.DateFieldType ||
|
|
|
+ fieldType instanceof DateFieldMapper.DateFieldType) {
|
|
|
+ // date
|
|
|
+ if (methodname == null) {
|
|
|
+ valueSource = DateField.getVariable(fieldData, fieldname, variablename);
|
|
|
+ } else {
|
|
|
+ valueSource = DateField.getMethod(fieldData, fieldname, methodname);
|
|
|
+ }
|
|
|
+ } else if (fieldData instanceof IndexNumericFieldData) {
|
|
|
+ // number
|
|
|
+ if (methodname == null) {
|
|
|
+ valueSource = NumericField.getVariable(fieldData, fieldname, variablename);
|
|
|
+ } else {
|
|
|
+ valueSource = NumericField.getMethod(fieldData, fieldname, methodname);
|
|
|
+ }
|
|
|
} else {
|
|
|
- bindings.add(variable, getMethodValueSource(fieldType, fieldData, fieldname, methodname));
|
|
|
+ throw new ScriptException("Field [" + fieldname + "] used in expression must be numeric, date, or geopoint");
|
|
|
}
|
|
|
+
|
|
|
+ bindings.add(variable, valueSource);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -224,57 +226,6 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- protected ValueSource getMethodValueSource(MappedFieldType fieldType, IndexFieldData<?> fieldData, String fieldName, String methodName) {
|
|
|
- switch (methodName) {
|
|
|
- case GET_YEAR_METHOD:
|
|
|
- return getDateMethodValueSource(fieldType, fieldData, fieldName, methodName, Calendar.YEAR);
|
|
|
- case GET_MONTH_METHOD:
|
|
|
- return getDateMethodValueSource(fieldType, fieldData, fieldName, methodName, Calendar.MONTH);
|
|
|
- case GET_DAY_OF_MONTH_METHOD:
|
|
|
- return getDateMethodValueSource(fieldType, fieldData, fieldName, methodName, Calendar.DAY_OF_MONTH);
|
|
|
- case GET_HOUR_OF_DAY_METHOD:
|
|
|
- return getDateMethodValueSource(fieldType, fieldData, fieldName, methodName, Calendar.HOUR_OF_DAY);
|
|
|
- case GET_MINUTES_METHOD:
|
|
|
- return getDateMethodValueSource(fieldType, fieldData, fieldName, methodName, Calendar.MINUTE);
|
|
|
- case GET_SECONDS_METHOD:
|
|
|
- return getDateMethodValueSource(fieldType, fieldData, fieldName, methodName, Calendar.SECOND);
|
|
|
- case MINIMUM_METHOD:
|
|
|
- return new FieldDataValueSource(fieldData, MultiValueMode.MIN);
|
|
|
- case MAXIMUM_METHOD:
|
|
|
- return new FieldDataValueSource(fieldData, MultiValueMode.MAX);
|
|
|
- case AVERAGE_METHOD:
|
|
|
- return new FieldDataValueSource(fieldData, MultiValueMode.AVG);
|
|
|
- case MEDIAN_METHOD:
|
|
|
- return new FieldDataValueSource(fieldData, MultiValueMode.MEDIAN);
|
|
|
- case SUM_METHOD:
|
|
|
- return new FieldDataValueSource(fieldData, MultiValueMode.SUM);
|
|
|
- case COUNT_METHOD:
|
|
|
- return new CountMethodValueSource(fieldData);
|
|
|
- default:
|
|
|
- throw new IllegalArgumentException("Member method [" + methodName + "] does not exist.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- protected ValueSource getVariableValueSource(MappedFieldType fieldType, IndexFieldData<?> fieldData, String fieldName, String memberName) {
|
|
|
- switch (memberName) {
|
|
|
- case VALUE_VARIABLE:
|
|
|
- return new FieldDataValueSource(fieldData, MultiValueMode.MIN);
|
|
|
- case EMPTY_VARIABLE:
|
|
|
- return new EmptyMemberValueSource(fieldData);
|
|
|
- default:
|
|
|
- throw new IllegalArgumentException("Member variable [" + memberName + "] does not exist.");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- protected ValueSource getDateMethodValueSource(MappedFieldType fieldType, IndexFieldData<?> fieldData, String fieldName, String methodName, int calendarType) {
|
|
|
- if (fieldType instanceof LegacyDateFieldMapper.DateFieldType == false
|
|
|
- && fieldType instanceof DateFieldMapper.DateFieldType == false) {
|
|
|
- throw new IllegalArgumentException("Member method [" + methodName + "] can only be used with a date field type, not the field [" + fieldName + "].");
|
|
|
- }
|
|
|
-
|
|
|
- return new DateMethodValueSource(fieldData, MultiValueMode.MIN, methodName, calendarType);
|
|
|
- }
|
|
|
-
|
|
|
@Override
|
|
|
public ExecutableScript executable(CompiledScript compiledScript, Map<String, Object> vars) {
|
|
|
return new ExpressionExecutableScript(compiledScript, vars);
|