Merge pull request #12280 from polyfractal/bugfix/movavg_validation
Aggregations: Add better validation of moving_avg model settings
This commit is contained in:
commit
380648ab86
|
@ -25,6 +25,7 @@ import org.elasticsearch.search.aggregations.pipeline.PipelineAggregatorBuilder;
|
|||
import org.elasticsearch.search.aggregations.pipeline.movavg.models.MovAvgModelBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A builder to create MovingAvg pipeline aggregations
|
||||
|
@ -37,6 +38,7 @@ public class MovAvgBuilder extends PipelineAggregatorBuilder<MovAvgBuilder> {
|
|||
private Integer window;
|
||||
private Integer predict;
|
||||
private Boolean minimize;
|
||||
private Map<String, Object> settings;
|
||||
|
||||
public MovAvgBuilder(String name) {
|
||||
super(name, MovAvgPipelineAggregator.TYPE.name());
|
||||
|
@ -107,6 +109,18 @@ public class MovAvgBuilder extends PipelineAggregatorBuilder<MovAvgBuilder> {
|
|||
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
|
||||
protected XContentBuilder internalXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
|
@ -128,6 +142,9 @@ public class MovAvgBuilder extends PipelineAggregatorBuilder<MovAvgBuilder> {
|
|||
if (minimize != null) {
|
||||
builder.field(MovAvgParser.MINIMIZE.getPreferredName(), minimize);
|
||||
}
|
||||
if (settings != null) {
|
||||
builder.field(MovAvgParser.SETTINGS.getPreferredName(), settings);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,9 +120,11 @@ public class EwmaModel extends MovAvgModel {
|
|||
}
|
||||
|
||||
@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);
|
||||
checkUnrecognizedParams(settings);
|
||||
return new EwmaModel(alpha);
|
||||
}
|
||||
|
||||
|
|
|
@ -180,10 +180,12 @@ public class HoltLinearModel extends MovAvgModel {
|
|||
}
|
||||
|
||||
@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 beta = parseDoubleParam(settings, "beta", 0.1);
|
||||
checkUnrecognizedParams(settings);
|
||||
return new HoltLinearModel(alpha, beta);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -356,7 +356,8 @@ public class HoltWintersModel extends MovAvgModel {
|
|||
}
|
||||
|
||||
@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 beta = parseDoubleParam(settings, "beta", 0.1);
|
||||
|
@ -376,6 +377,7 @@ public class HoltWintersModel extends MovAvgModel {
|
|||
if (value != null) {
|
||||
if (value instanceof String) {
|
||||
seasonalityType = SeasonalityType.parse((String)value, parseFieldMatcher);
|
||||
settings.remove("type");
|
||||
} else {
|
||||
throw new ParseException("Parameter [type] must be a String, type `"
|
||||
+ value.getClass().getSimpleName() + "` provided instead", 0);
|
||||
|
@ -385,6 +387,7 @@ public class HoltWintersModel extends MovAvgModel {
|
|||
|
||||
boolean pad = parseBoolParam(settings, "pad", seasonalityType.equals(SeasonalityType.MULTIPLICATIVE));
|
||||
|
||||
checkUnrecognizedParams(settings);
|
||||
return new HoltWintersModel(alpha, beta, gamma, period, seasonalityType, pad);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,7 +107,9 @@ public class LinearModel extends MovAvgModel {
|
|||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,8 @@ public abstract class MovAvgModel {
|
|||
* @param parseFieldMatcher Matcher for field names
|
||||
* @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) {
|
||||
double v = ((Number) value).doubleValue();
|
||||
if (v >= 0 && v <= 1) {
|
||||
settings.remove(name);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -211,6 +213,7 @@ public abstract class MovAvgModel {
|
|||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else if (value instanceof Number) {
|
||||
settings.remove(name);
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
|
||||
|
@ -238,12 +241,19 @@ public abstract class MovAvgModel {
|
|||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else if (value instanceof Boolean) {
|
||||
settings.remove(name);
|
||||
return (Boolean)value;
|
||||
}
|
||||
|
||||
throw new ParseException("Parameter [" + name + "] must be a boolean, type `"
|
||||
+ 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) {
|
||||
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));
|
||||
|
||||
return predictions;
|
||||
|
@ -100,7 +100,9 @@ public class SimpleModel extends MovAvgModel {
|
|||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import com.google.common.collect.EvictingQueue;
|
|||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||
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.InternalHistogram;
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 (Object v : values) {
|
||||
settings.put("alpha", v);
|
||||
settings.put("beta", v);
|
||||
settings.put("gamma", v);
|
||||
|
||||
try {
|
||||
parser.parse(settings, "pipeline", 10, ParseFieldMatcher.STRICT);
|
||||
|
|
Loading…
Reference in New Issue