Aggregations: Add better validation of moving_avg model settings
This commit is contained in:
parent
901421bc14
commit
702f884ba0
|
@ -25,6 +25,7 @@ import org.elasticsearch.search.aggregations.pipeline.PipelineAggregatorBuilder;
|
||||||
import org.elasticsearch.search.aggregations.pipeline.movavg.models.MovAvgModelBuilder;
|
import org.elasticsearch.search.aggregations.pipeline.movavg.models.MovAvgModelBuilder;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder to create MovingAvg pipeline aggregations
|
* A builder to create MovingAvg pipeline aggregations
|
||||||
|
@ -37,6 +38,7 @@ public class MovAvgBuilder extends PipelineAggregatorBuilder<MovAvgBuilder> {
|
||||||
private Integer window;
|
private Integer window;
|
||||||
private Integer predict;
|
private Integer predict;
|
||||||
private Boolean minimize;
|
private Boolean minimize;
|
||||||
|
private Map<String, Object> settings;
|
||||||
|
|
||||||
public MovAvgBuilder(String name) {
|
public MovAvgBuilder(String name) {
|
||||||
super(name, MovAvgPipelineAggregator.TYPE.name());
|
super(name, MovAvgPipelineAggregator.TYPE.name());
|
||||||
|
@ -107,6 +109,18 @@ public class MovAvgBuilder extends PipelineAggregatorBuilder<MovAvgBuilder> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hash of settings that should be provided to the model when it is
|
||||||
|
* instantiated
|
||||||
|
*
|
||||||
|
* @param settings
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public MovAvgBuilder settings(Map<String, Object> settings) {
|
||||||
|
this.settings = settings;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
|
protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
@ -128,6 +142,9 @@ public class MovAvgBuilder extends PipelineAggregatorBuilder<MovAvgBuilder> {
|
||||||
if (minimize != null) {
|
if (minimize != null) {
|
||||||
builder.field(MovAvgParser.MINIMIZE.getPreferredName(), minimize);
|
builder.field(MovAvgParser.MINIMIZE.getPreferredName(), minimize);
|
||||||
}
|
}
|
||||||
|
if (settings != null) {
|
||||||
|
builder.field(MovAvgParser.SETTINGS.getPreferredName(), settings);
|
||||||
|
}
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,9 +120,11 @@ public class EwmaModel extends MovAvgModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize, ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize,
|
||||||
|
ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
||||||
|
|
||||||
double alpha = parseDoubleParam(settings, "alpha", 0.3);
|
double alpha = parseDoubleParam(settings, "alpha", 0.3);
|
||||||
|
checkUnrecognizedParams(settings);
|
||||||
return new EwmaModel(alpha);
|
return new EwmaModel(alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,10 +180,12 @@ public class HoltLinearModel extends MovAvgModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize, ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize,
|
||||||
|
ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
||||||
|
|
||||||
double alpha = parseDoubleParam(settings, "alpha", 0.3);
|
double alpha = parseDoubleParam(settings, "alpha", 0.3);
|
||||||
double beta = parseDoubleParam(settings, "beta", 0.1);
|
double beta = parseDoubleParam(settings, "beta", 0.1);
|
||||||
|
checkUnrecognizedParams(settings);
|
||||||
return new HoltLinearModel(alpha, beta);
|
return new HoltLinearModel(alpha, beta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,7 +356,8 @@ public class HoltWintersModel extends MovAvgModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize, ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize,
|
||||||
|
ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
||||||
|
|
||||||
double alpha = parseDoubleParam(settings, "alpha", 0.3);
|
double alpha = parseDoubleParam(settings, "alpha", 0.3);
|
||||||
double beta = parseDoubleParam(settings, "beta", 0.1);
|
double beta = parseDoubleParam(settings, "beta", 0.1);
|
||||||
|
@ -376,6 +377,7 @@ public class HoltWintersModel extends MovAvgModel {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (value instanceof String) {
|
if (value instanceof String) {
|
||||||
seasonalityType = SeasonalityType.parse((String)value, parseFieldMatcher);
|
seasonalityType = SeasonalityType.parse((String)value, parseFieldMatcher);
|
||||||
|
settings.remove("type");
|
||||||
} else {
|
} else {
|
||||||
throw new ParseException("Parameter [type] must be a String, type `"
|
throw new ParseException("Parameter [type] must be a String, type `"
|
||||||
+ value.getClass().getSimpleName() + "` provided instead", 0);
|
+ value.getClass().getSimpleName() + "` provided instead", 0);
|
||||||
|
@ -385,6 +387,7 @@ public class HoltWintersModel extends MovAvgModel {
|
||||||
|
|
||||||
boolean pad = parseBoolParam(settings, "pad", seasonalityType.equals(SeasonalityType.MULTIPLICATIVE));
|
boolean pad = parseBoolParam(settings, "pad", seasonalityType.equals(SeasonalityType.MULTIPLICATIVE));
|
||||||
|
|
||||||
|
checkUnrecognizedParams(settings);
|
||||||
return new HoltWintersModel(alpha, beta, gamma, period, seasonalityType, pad);
|
return new HoltWintersModel(alpha, beta, gamma, period, seasonalityType, pad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,7 +107,9 @@ public class LinearModel extends MovAvgModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize, ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize,
|
||||||
|
ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
||||||
|
checkUnrecognizedParams(settings);
|
||||||
return new LinearModel();
|
return new LinearModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,8 @@ public abstract class MovAvgModel {
|
||||||
* @param parseFieldMatcher Matcher for field names
|
* @param parseFieldMatcher Matcher for field names
|
||||||
* @return A fully built moving average model
|
* @return A fully built moving average model
|
||||||
*/
|
*/
|
||||||
public abstract MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize, ParseFieldMatcher parseFieldMatcher) throws ParseException;
|
public abstract MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName,
|
||||||
|
int windowSize, ParseFieldMatcher parseFieldMatcher) throws ParseException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,6 +181,7 @@ public abstract class MovAvgModel {
|
||||||
} else if (value instanceof Number) {
|
} else if (value instanceof Number) {
|
||||||
double v = ((Number) value).doubleValue();
|
double v = ((Number) value).doubleValue();
|
||||||
if (v >= 0 && v <= 1) {
|
if (v >= 0 && v <= 1) {
|
||||||
|
settings.remove(name);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +213,7 @@ public abstract class MovAvgModel {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
} else if (value instanceof Number) {
|
} else if (value instanceof Number) {
|
||||||
|
settings.remove(name);
|
||||||
return ((Number) value).intValue();
|
return ((Number) value).intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,12 +241,19 @@ public abstract class MovAvgModel {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
} else if (value instanceof Boolean) {
|
} else if (value instanceof Boolean) {
|
||||||
|
settings.remove(name);
|
||||||
return (Boolean)value;
|
return (Boolean)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ParseException("Parameter [" + name + "] must be a boolean, type `"
|
throw new ParseException("Parameter [" + name + "] must be a boolean, type `"
|
||||||
+ value.getClass().getSimpleName() + "` provided instead", 0);
|
+ value.getClass().getSimpleName() + "` provided instead", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkUnrecognizedParams(@Nullable Map<String, Object> settings) throws ParseException {
|
||||||
|
if (settings != null && settings.size() > 0) {
|
||||||
|
throw new ParseException("Unrecognized parameter(s): [" + String.join(", ", settings.keySet()) + "]", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class SimpleModel extends MovAvgModel {
|
||||||
protected <T extends Number> double[] doPredict(Collection<T> values, int numPredictions) {
|
protected <T extends Number> double[] doPredict(Collection<T> values, int numPredictions) {
|
||||||
double[] predictions = new double[numPredictions];
|
double[] predictions = new double[numPredictions];
|
||||||
|
|
||||||
// EWMA just emits the same final prediction repeatedly.
|
// Simple just emits the same final prediction repeatedly.
|
||||||
Arrays.fill(predictions, next(values));
|
Arrays.fill(predictions, next(values));
|
||||||
|
|
||||||
return predictions;
|
return predictions;
|
||||||
|
@ -100,7 +100,9 @@ public class SimpleModel extends MovAvgModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize, ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
public MovAvgModel parse(@Nullable Map<String, Object> settings, String pipelineName, int windowSize,
|
||||||
|
ParseFieldMatcher parseFieldMatcher) throws ParseException {
|
||||||
|
checkUnrecognizedParams(settings);
|
||||||
return new SimpleModel();
|
return new SimpleModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import com.google.common.collect.EvictingQueue;
|
||||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.search.SearchParseException;
|
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
|
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.InternalHistogram;
|
import org.elasticsearch.search.aggregations.bucket.histogram.InternalHistogram;
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.InternalHistogram.Bucket;
|
import org.elasticsearch.search.aggregations.bucket.histogram.InternalHistogram.Bucket;
|
||||||
|
@ -1265,6 +1264,42 @@ public class MovAvgTests extends ElasticsearchIntegrationTest {
|
||||||
fail("Model [" + builder.toString() + "] can be minimized, but an exception was thrown");
|
fail("Model [" + builder.toString() + "] can be minimized, but an exception was thrown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnrecognizedParams() {
|
||||||
|
|
||||||
|
MovAvgModelBuilder[] builders = new MovAvgModelBuilder[]{
|
||||||
|
new SimpleModel.SimpleModelBuilder(),
|
||||||
|
new LinearModel.LinearModelBuilder(),
|
||||||
|
new EwmaModel.EWMAModelBuilder(),
|
||||||
|
new HoltLinearModel.HoltLinearModelBuilder(),
|
||||||
|
new HoltWintersModel.HoltWintersModelBuilder()
|
||||||
|
};
|
||||||
|
Map<String, Object> badSettings = new HashMap<>(1);
|
||||||
|
badSettings.put("abc", 1.2);
|
||||||
|
|
||||||
|
for (MovAvgModelBuilder builder : builders) {
|
||||||
|
try {
|
||||||
|
SearchResponse response = client()
|
||||||
|
.prepareSearch("idx").setTypes("type")
|
||||||
|
.addAggregation(
|
||||||
|
histogram("histo").field(INTERVAL_FIELD).interval(interval)
|
||||||
|
.extendedBounds(0L, (long) (interval * (numBuckets - 1)))
|
||||||
|
.subAggregation(metric)
|
||||||
|
.subAggregation(movingAvg("movavg_counts")
|
||||||
|
.window(10)
|
||||||
|
.modelBuilder(builder)
|
||||||
|
.gapPolicy(gapPolicy)
|
||||||
|
.settings(badSettings)
|
||||||
|
.setBucketsPaths("_count"))
|
||||||
|
).execute().actionGet();
|
||||||
|
} catch (SearchPhaseExecutionException e) {
|
||||||
|
// All good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -611,8 +611,6 @@ public class MovAvgUnitTests extends ElasticsearchTestCase {
|
||||||
for (MovAvgModel.AbstractModelParser parser : parsers) {
|
for (MovAvgModel.AbstractModelParser parser : parsers) {
|
||||||
for (Object v : values) {
|
for (Object v : values) {
|
||||||
settings.put("alpha", v);
|
settings.put("alpha", v);
|
||||||
settings.put("beta", v);
|
|
||||||
settings.put("gamma", v);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
parser.parse(settings, "pipeline", 10, ParseFieldMatcher.STRICT);
|
parser.parse(settings, "pipeline", 10, ParseFieldMatcher.STRICT);
|
||||||
|
|
Loading…
Reference in New Issue