From 756d87898360c4e80fcc6a421d0a5255047e96ef Mon Sep 17 00:00:00 2001 From: Hendrik Muhs Date: Thu, 30 Nov 2017 07:49:21 +0100 Subject: [PATCH] [ML-FC] do not allow durations below the bucket span (elastic/x-pack-elasticsearch#3166) do not allow durations below the bucket span Original commit: elastic/x-pack-elasticsearch@0e895c1dddb9283cc8cd88f0203329ce90c8011d --- .../xpack/ml/action/ForecastJobAction.java | 18 ++++++++++++++- .../xpack/ml/integration/ForecastIT.java | 22 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/action/ForecastJobAction.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/action/ForecastJobAction.java index 4990e0201ec..e3dc4e94466 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/action/ForecastJobAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/action/ForecastJobAction.java @@ -26,6 +26,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; +import org.elasticsearch.xpack.ml.job.JobManager; import org.elasticsearch.xpack.ml.job.config.Job; import org.elasticsearch.xpack.ml.job.process.autodetect.AutodetectProcessManager; import org.elasticsearch.xpack.ml.job.process.autodetect.params.ForecastParams; @@ -34,6 +35,8 @@ import org.elasticsearch.xpack.ml.job.results.Forecast; import java.io.IOException; import java.util.Objects; +import static org.elasticsearch.xpack.ml.action.ForecastJobAction.Request.DURATION; + public class ForecastJobAction extends Action { public static final ForecastJobAction INSTANCE = new ForecastJobAction(); @@ -244,13 +247,16 @@ public class ForecastJobAction extends Action { + private final JobManager jobManager; + @Inject public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ClusterService clusterService, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver, - AutodetectProcessManager processManager) { + JobManager jobManager, AutodetectProcessManager processManager) { super(settings, ForecastJobAction.NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver, ForecastJobAction.Request::new, ForecastJobAction.Response::new, ThreadPool.Names.SAME, processManager); + this.jobManager = jobManager; // ThreadPool.Names.SAME, because operations is executed by autodetect worker thread } @@ -265,6 +271,16 @@ public class ForecastJobAction extends Action listener) { ForecastParams.Builder paramsBuilder = ForecastParams.builder(); if (request.getDuration() != null) { + TimeValue duration = request.getDuration(); + TimeValue bucketSpan = jobManager.getJobOrThrowIfUnknown(task.getJobId()).getAnalysisConfig().getBucketSpan(); + + if (duration.compareTo(bucketSpan) < 0) { + throw new IllegalArgumentException( + "[" + DURATION.getPreferredName() + + "] must be greater or equal to the bucket span: [" + + duration.getStringRep() + "/" + bucketSpan.getStringRep() + "]"); + } + paramsBuilder.duration(request.getDuration()); } if (request.getExpiresIn() != null) { diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/ForecastIT.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/ForecastIT.java index 2c9742b67fb..b411c6d8f67 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/ForecastIT.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/ForecastIT.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.ml.integration; +import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.xpack.ml.job.config.AnalysisConfig; import org.elasticsearch.xpack.ml.job.config.DataDescription; @@ -134,6 +135,27 @@ public class ForecastIT extends MlNativeAutodetectIntegTestCase { } } + public void testDurationCannotBeLessThanBucketSpan() throws Exception { + Detector.Builder detector = new Detector.Builder("mean", "value"); + + TimeValue bucketSpan = TimeValue.timeValueHours(1); + AnalysisConfig.Builder analysisConfig = new AnalysisConfig.Builder(Collections.singletonList(detector.build())); + analysisConfig.setBucketSpan(bucketSpan); + DataDescription.Builder dataDescription = new DataDescription.Builder(); + dataDescription.setTimeFormat("epoch"); + Job.Builder job = new Job.Builder("forecast-it-test-duration-bucket-span"); + job.setAnalysisConfig(analysisConfig); + job.setDataDescription(dataDescription); + + registerJob(job); + putJob(job); + openJob(job.getId()); + ElasticsearchException e = expectThrows(ElasticsearchException.class,() -> forecast(job.getId(), + TimeValue.timeValueMinutes(10), null)); + assertThat(e.getMessage(), + equalTo("java.lang.IllegalArgumentException: [duration] must be greater or equal to the bucket span: [10m/1h]")); + } + private static Map createRecord(long timestamp, double value) { Map record = new HashMap<>(); record.put("time", timestamp);