From de1cb600445d8c8567ace6426078386943a252c2 Mon Sep 17 00:00:00 2001 From: Ed Savage Date: Tue, 2 Oct 2018 16:03:39 +0100 Subject: [PATCH 1/2] [ML] Label anomalies with multi_bucket_impact Add the multi_bucket_impact field to record results. --- .../client/ml/job/results/AnomalyRecord.java | 15 ++++++++++++++- .../ml/job/results/AnomalyRecordTests.java | 1 + docs/reference/ml/apis/resultsresource.asciidoc | 5 +++++ .../job/persistence/ElasticsearchMappings.java | 3 +++ .../core/ml/job/results/AnomalyRecord.java | 17 ++++++++++++++++- .../core/ml/job/results/ReservedFieldNames.java | 1 + .../core/ml/job/results/AnomalyRecordTests.java | 1 + 7 files changed, 41 insertions(+), 2 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java index c10610a872f17..f2839c0c0be86 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java @@ -48,6 +48,7 @@ public class AnomalyRecord implements ToXContentObject { * Result fields (all detector types) */ public static final ParseField PROBABILITY = new ParseField("probability"); + public static final ParseField IMPACT = new ParseField("multi_bucket_impact"); public static final ParseField DETECTOR_INDEX = new ParseField("detector_index"); public static final ParseField BY_FIELD_NAME = new ParseField("by_field_name"); public static final ParseField BY_FIELD_VALUE = new ParseField("by_field_value"); @@ -94,6 +95,7 @@ public class AnomalyRecord implements ToXContentObject { PARSER.declareLong(ConstructingObjectParser.constructorArg(), BUCKET_SPAN); PARSER.declareString((anomalyRecord, s) -> {}, Result.RESULT_TYPE); PARSER.declareDouble(AnomalyRecord::setProbability, PROBABILITY); + PARSER.declareDouble(AnomalyRecord::setImpact, IMPACT); PARSER.declareDouble(AnomalyRecord::setRecordScore, RECORD_SCORE); PARSER.declareDouble(AnomalyRecord::setInitialRecordScore, INITIAL_RECORD_SCORE); PARSER.declareInt(AnomalyRecord::setDetectorIndex, DETECTOR_INDEX); @@ -117,6 +119,7 @@ public class AnomalyRecord implements ToXContentObject { private final String jobId; private int detectorIndex; private double probability; + private double impact; private String byFieldName; private String byFieldValue; private String correlatedByFieldValue; @@ -155,6 +158,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(Job.ID.getPreferredName(), jobId); builder.field(Result.RESULT_TYPE.getPreferredName(), RESULT_TYPE_VALUE); builder.field(PROBABILITY.getPreferredName(), probability); + builder.field(IMPACT.getPreferredName(), impact); builder.field(RECORD_SCORE.getPreferredName(), recordScore); builder.field(INITIAL_RECORD_SCORE.getPreferredName(), initialRecordScore); builder.field(BUCKET_SPAN.getPreferredName(), bucketSpan); @@ -254,6 +258,14 @@ void setProbability(double value) { probability = value; } + public double getImpact() { + return impact; + } + + void setImpact(double value) { + impact = value; + } + public String getByFieldName() { return byFieldName; } @@ -376,7 +388,7 @@ void setInfluencers(List influencers) { @Override public int hashCode() { - return Objects.hash(jobId, detectorIndex, bucketSpan, probability, recordScore, + return Objects.hash(jobId, detectorIndex, bucketSpan, probability, impact, recordScore, initialRecordScore, typical, actual,function, functionDescription, fieldName, byFieldName, byFieldValue, correlatedByFieldValue, partitionFieldName, partitionFieldValue, overFieldName, overFieldValue, timestamp, isInterim, @@ -399,6 +411,7 @@ public boolean equals(Object other) { && this.detectorIndex == that.detectorIndex && this.bucketSpan == that.bucketSpan && this.probability == that.probability + && this.impact == that.impact && this.recordScore == that.recordScore && this.initialRecordScore == that.initialRecordScore && Objects.deepEquals(this.typical, that.typical) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java index a857cd3d9b10f..35cf3755abaac 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java @@ -38,6 +38,7 @@ public static AnomalyRecord createTestInstance(String jobId) { anomalyRecord.setActual(Collections.singletonList(randomDouble())); anomalyRecord.setTypical(Collections.singletonList(randomDouble())); anomalyRecord.setProbability(randomDouble()); + anomalyRecord.setImpact(randomDouble()); anomalyRecord.setRecordScore(randomDouble()); anomalyRecord.setInitialRecordScore(randomDouble()); anomalyRecord.setInterim(randomBoolean()); diff --git a/docs/reference/ml/apis/resultsresource.asciidoc b/docs/reference/ml/apis/resultsresource.asciidoc index d3abd094be79c..9aac36fc87ae1 100644 --- a/docs/reference/ml/apis/resultsresource.asciidoc +++ b/docs/reference/ml/apis/resultsresource.asciidoc @@ -364,6 +364,11 @@ A record object has the following properties: //In scientific notation, a value of 3.24E-300 is highly unlikely and therefore //highly anomalous. +`multi_bucket_impact`:: + (number) an indication of how strongly an anomaly is multi bucket or single bucket. + The value is on a scale of -5 to +5 where -5 means the anomaly is purely single + bucket and +5 means the anomaly is purely multi bucket. + `record_score`:: (number) A normalized score between 0-100, which is based on the probability of the anomalousness of this record. Unlike `initial_record_score`, this diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java index 316417f4b23aa..332a8c3f1fd45 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java @@ -372,6 +372,9 @@ private static void addAnomalyRecordFieldsToMapping(XContentBuilder builder) thr .startObject(AnomalyRecord.PROBABILITY.getPreferredName()) .field(TYPE, DOUBLE) .endObject() + .startObject(AnomalyRecord.IMPACT.getPreferredName()) + .field(TYPE, DOUBLE) + .endObject() .startObject(AnomalyRecord.FUNCTION.getPreferredName()) .field(TYPE, KEYWORD) .endObject() diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java index 869cdcb437e1f..0c21a62ff4f8f 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java @@ -44,6 +44,7 @@ public class AnomalyRecord implements ToXContentObject, Writeable { * Result fields (all detector types) */ public static final ParseField PROBABILITY = new ParseField("probability"); + public static final ParseField IMPACT = new ParseField("multi_bucket_impact"); public static final ParseField BY_FIELD_NAME = new ParseField("by_field_name"); public static final ParseField BY_FIELD_VALUE = new ParseField("by_field_value"); public static final ParseField CORRELATED_BY_FIELD_VALUE = new ParseField("correlated_by_field_value"); @@ -100,6 +101,7 @@ private static ConstructingObjectParser createParser(boolea parser.declareLong(ConstructingObjectParser.constructorArg(), BUCKET_SPAN); parser.declareString((anomalyRecord, s) -> {}, Result.RESULT_TYPE); parser.declareDouble(AnomalyRecord::setProbability, PROBABILITY); + parser.declareDouble(AnomalyRecord::setImpact, IMPACT); parser.declareDouble(AnomalyRecord::setRecordScore, RECORD_SCORE); parser.declareDouble(AnomalyRecord::setInitialRecordScore, INITIAL_RECORD_SCORE); parser.declareInt(AnomalyRecord::setDetectorIndex, Detector.DETECTOR_INDEX); @@ -127,6 +129,7 @@ private static ConstructingObjectParser createParser(boolea private final String jobId; private int detectorIndex; private double probability; + private double impact; private String byFieldName; private String byFieldValue; private String correlatedByFieldValue; @@ -164,6 +167,7 @@ public AnomalyRecord(StreamInput in) throws IOException { jobId = in.readString(); detectorIndex = in.readInt(); probability = in.readDouble(); + impact = in.readDouble(); byFieldName = in.readOptionalString(); byFieldValue = in.readOptionalString(); correlatedByFieldValue = in.readOptionalString(); @@ -198,6 +202,7 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(jobId); out.writeInt(detectorIndex); out.writeDouble(probability); + out.writeDouble(impact); out.writeOptionalString(byFieldName); out.writeOptionalString(byFieldValue); out.writeOptionalString(correlatedByFieldValue); @@ -247,6 +252,7 @@ XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws I builder.field(Job.ID.getPreferredName(), jobId); builder.field(Result.RESULT_TYPE.getPreferredName(), RESULT_TYPE_VALUE); builder.field(PROBABILITY.getPreferredName(), probability); + builder.field(IMPACT.getPreferredName(), impact); builder.field(RECORD_SCORE.getPreferredName(), recordScore); builder.field(INITIAL_RECORD_SCORE.getPreferredName(), initialRecordScore); builder.field(BUCKET_SPAN.getPreferredName(), bucketSpan); @@ -389,6 +395,14 @@ public void setProbability(double value) { probability = value; } + public double getImpact() { + return impact; + } + + public void setImpact(double value) { + impact = value; + } + public String getByFieldName() { return byFieldName; } @@ -519,7 +533,7 @@ public void setInfluencers(List influencers) { @Override public int hashCode() { - return Objects.hash(jobId, detectorIndex, bucketSpan, probability, recordScore, + return Objects.hash(jobId, detectorIndex, bucketSpan, probability, impact, recordScore, initialRecordScore, typical, actual,function, functionDescription, fieldName, byFieldName, byFieldValue, correlatedByFieldValue, partitionFieldName, partitionFieldValue, overFieldName, overFieldValue, timestamp, isInterim, @@ -543,6 +557,7 @@ public boolean equals(Object other) { && this.detectorIndex == that.detectorIndex && this.bucketSpan == that.bucketSpan && this.probability == that.probability + && this.impact == that.impact && this.recordScore == that.recordScore && this.initialRecordScore == that.initialRecordScore && Objects.deepEquals(this.typical, that.typical) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java index 63c4278e541d4..d68a2a1de36a9 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java @@ -57,6 +57,7 @@ public final class ReservedFieldNames { AnomalyCause.FIELD_NAME.getPreferredName(), AnomalyRecord.PROBABILITY.getPreferredName(), + AnomalyRecord.IMPACT.getPreferredName(), AnomalyRecord.BY_FIELD_NAME.getPreferredName(), AnomalyRecord.BY_FIELD_VALUE.getPreferredName(), AnomalyRecord.CORRELATED_BY_FIELD_VALUE.getPreferredName(), diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java index fc2ee52dc41ba..1640526bf6495 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java @@ -37,6 +37,7 @@ public AnomalyRecord createTestInstance(String jobId) { anomalyRecord.setActual(Collections.singletonList(randomDouble())); anomalyRecord.setTypical(Collections.singletonList(randomDouble())); anomalyRecord.setProbability(randomDouble()); + anomalyRecord.setImpact(randomDouble()); anomalyRecord.setRecordScore(randomDouble()); anomalyRecord.setInitialRecordScore(randomDouble()); anomalyRecord.setInterim(randomBoolean()); From aa92994a0f5ea7a3c54e897d2e2c2303dbccebeb Mon Sep 17 00:00:00 2001 From: Ed Savage Date: Wed, 3 Oct 2018 10:40:53 +0100 Subject: [PATCH 2/2] Attending to code review comments --- .../client/ml/job/results/AnomalyRecord.java | 22 +++++++------ .../ml/job/results/AnomalyRecordTests.java | 4 ++- .../persistence/ElasticsearchMappings.java | 2 +- .../core/ml/job/results/AnomalyRecord.java | 31 ++++++++++++------- .../ml/job/results/ReservedFieldNames.java | 2 +- .../ml/job/results/AnomalyRecordTests.java | 4 ++- 6 files changed, 39 insertions(+), 26 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java index f2839c0c0be86..3f743b3642256 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ml/job/results/AnomalyRecord.java @@ -48,7 +48,7 @@ public class AnomalyRecord implements ToXContentObject { * Result fields (all detector types) */ public static final ParseField PROBABILITY = new ParseField("probability"); - public static final ParseField IMPACT = new ParseField("multi_bucket_impact"); + public static final ParseField MULTI_BUCKET_IMPACT = new ParseField("multi_bucket_impact"); public static final ParseField DETECTOR_INDEX = new ParseField("detector_index"); public static final ParseField BY_FIELD_NAME = new ParseField("by_field_name"); public static final ParseField BY_FIELD_VALUE = new ParseField("by_field_value"); @@ -95,7 +95,7 @@ public class AnomalyRecord implements ToXContentObject { PARSER.declareLong(ConstructingObjectParser.constructorArg(), BUCKET_SPAN); PARSER.declareString((anomalyRecord, s) -> {}, Result.RESULT_TYPE); PARSER.declareDouble(AnomalyRecord::setProbability, PROBABILITY); - PARSER.declareDouble(AnomalyRecord::setImpact, IMPACT); + PARSER.declareDouble(AnomalyRecord::setMultiBucketImpact, MULTI_BUCKET_IMPACT); PARSER.declareDouble(AnomalyRecord::setRecordScore, RECORD_SCORE); PARSER.declareDouble(AnomalyRecord::setInitialRecordScore, INITIAL_RECORD_SCORE); PARSER.declareInt(AnomalyRecord::setDetectorIndex, DETECTOR_INDEX); @@ -119,7 +119,7 @@ public class AnomalyRecord implements ToXContentObject { private final String jobId; private int detectorIndex; private double probability; - private double impact; + private Double multiBucketImpact; private String byFieldName; private String byFieldValue; private String correlatedByFieldValue; @@ -158,7 +158,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.field(Job.ID.getPreferredName(), jobId); builder.field(Result.RESULT_TYPE.getPreferredName(), RESULT_TYPE_VALUE); builder.field(PROBABILITY.getPreferredName(), probability); - builder.field(IMPACT.getPreferredName(), impact); + if (multiBucketImpact != null) { + builder.field(MULTI_BUCKET_IMPACT.getPreferredName(), multiBucketImpact); + } builder.field(RECORD_SCORE.getPreferredName(), recordScore); builder.field(INITIAL_RECORD_SCORE.getPreferredName(), initialRecordScore); builder.field(BUCKET_SPAN.getPreferredName(), bucketSpan); @@ -258,12 +260,12 @@ void setProbability(double value) { probability = value; } - public double getImpact() { - return impact; + public double getMultiBucketImpact() { + return multiBucketImpact; } - void setImpact(double value) { - impact = value; + void setMultiBucketImpact(double value) { + multiBucketImpact = value; } public String getByFieldName() { @@ -388,7 +390,7 @@ void setInfluencers(List influencers) { @Override public int hashCode() { - return Objects.hash(jobId, detectorIndex, bucketSpan, probability, impact, recordScore, + return Objects.hash(jobId, detectorIndex, bucketSpan, probability, multiBucketImpact, recordScore, initialRecordScore, typical, actual,function, functionDescription, fieldName, byFieldName, byFieldValue, correlatedByFieldValue, partitionFieldName, partitionFieldValue, overFieldName, overFieldValue, timestamp, isInterim, @@ -411,7 +413,7 @@ public boolean equals(Object other) { && this.detectorIndex == that.detectorIndex && this.bucketSpan == that.bucketSpan && this.probability == that.probability - && this.impact == that.impact + && Objects.equals(this.multiBucketImpact, that.multiBucketImpact) && this.recordScore == that.recordScore && this.initialRecordScore == that.initialRecordScore && Objects.deepEquals(this.typical, that.typical) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java index 35cf3755abaac..39bfff3a7e8f9 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ml/job/results/AnomalyRecordTests.java @@ -38,7 +38,9 @@ public static AnomalyRecord createTestInstance(String jobId) { anomalyRecord.setActual(Collections.singletonList(randomDouble())); anomalyRecord.setTypical(Collections.singletonList(randomDouble())); anomalyRecord.setProbability(randomDouble()); - anomalyRecord.setImpact(randomDouble()); + if (randomBoolean()) { + anomalyRecord.setMultiBucketImpact(randomDouble()); + } anomalyRecord.setRecordScore(randomDouble()); anomalyRecord.setInitialRecordScore(randomDouble()); anomalyRecord.setInterim(randomBoolean()); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java index 332a8c3f1fd45..d95b404ed3571 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/persistence/ElasticsearchMappings.java @@ -372,7 +372,7 @@ private static void addAnomalyRecordFieldsToMapping(XContentBuilder builder) thr .startObject(AnomalyRecord.PROBABILITY.getPreferredName()) .field(TYPE, DOUBLE) .endObject() - .startObject(AnomalyRecord.IMPACT.getPreferredName()) + .startObject(AnomalyRecord.MULTI_BUCKET_IMPACT.getPreferredName()) .field(TYPE, DOUBLE) .endObject() .startObject(AnomalyRecord.FUNCTION.getPreferredName()) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java index 0c21a62ff4f8f..1deabbc69df64 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecord.java @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.core.ml.job.config.Job; import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper; import org.elasticsearch.xpack.core.ml.utils.time.TimeUtils; +import org.elasticsearch.Version; import java.io.IOException; import java.util.ArrayList; @@ -44,7 +45,7 @@ public class AnomalyRecord implements ToXContentObject, Writeable { * Result fields (all detector types) */ public static final ParseField PROBABILITY = new ParseField("probability"); - public static final ParseField IMPACT = new ParseField("multi_bucket_impact"); + public static final ParseField MULTI_BUCKET_IMPACT = new ParseField("multi_bucket_impact"); public static final ParseField BY_FIELD_NAME = new ParseField("by_field_name"); public static final ParseField BY_FIELD_VALUE = new ParseField("by_field_value"); public static final ParseField CORRELATED_BY_FIELD_VALUE = new ParseField("correlated_by_field_value"); @@ -101,7 +102,7 @@ private static ConstructingObjectParser createParser(boolea parser.declareLong(ConstructingObjectParser.constructorArg(), BUCKET_SPAN); parser.declareString((anomalyRecord, s) -> {}, Result.RESULT_TYPE); parser.declareDouble(AnomalyRecord::setProbability, PROBABILITY); - parser.declareDouble(AnomalyRecord::setImpact, IMPACT); + parser.declareDouble(AnomalyRecord::setMultiBucketImpact, MULTI_BUCKET_IMPACT); parser.declareDouble(AnomalyRecord::setRecordScore, RECORD_SCORE); parser.declareDouble(AnomalyRecord::setInitialRecordScore, INITIAL_RECORD_SCORE); parser.declareInt(AnomalyRecord::setDetectorIndex, Detector.DETECTOR_INDEX); @@ -129,7 +130,7 @@ private static ConstructingObjectParser createParser(boolea private final String jobId; private int detectorIndex; private double probability; - private double impact; + private Double multiBucketImpact; private String byFieldName; private String byFieldValue; private String correlatedByFieldValue; @@ -167,7 +168,9 @@ public AnomalyRecord(StreamInput in) throws IOException { jobId = in.readString(); detectorIndex = in.readInt(); probability = in.readDouble(); - impact = in.readDouble(); + if (in.getVersion().onOrAfter(Version.V_6_5_0)) { + multiBucketImpact = in.readOptionalDouble(); + } byFieldName = in.readOptionalString(); byFieldValue = in.readOptionalString(); correlatedByFieldValue = in.readOptionalString(); @@ -202,7 +205,9 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(jobId); out.writeInt(detectorIndex); out.writeDouble(probability); - out.writeDouble(impact); + if (out.getVersion().onOrAfter(Version.V_6_5_0)) { + out.writeOptionalDouble(multiBucketImpact); + } out.writeOptionalString(byFieldName); out.writeOptionalString(byFieldValue); out.writeOptionalString(correlatedByFieldValue); @@ -252,7 +257,9 @@ XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws I builder.field(Job.ID.getPreferredName(), jobId); builder.field(Result.RESULT_TYPE.getPreferredName(), RESULT_TYPE_VALUE); builder.field(PROBABILITY.getPreferredName(), probability); - builder.field(IMPACT.getPreferredName(), impact); + if (multiBucketImpact != null) { + builder.field(MULTI_BUCKET_IMPACT.getPreferredName(), multiBucketImpact); + } builder.field(RECORD_SCORE.getPreferredName(), recordScore); builder.field(INITIAL_RECORD_SCORE.getPreferredName(), initialRecordScore); builder.field(BUCKET_SPAN.getPreferredName(), bucketSpan); @@ -395,12 +402,12 @@ public void setProbability(double value) { probability = value; } - public double getImpact() { - return impact; + public double getMultiBucketImpact() { + return multiBucketImpact; } - public void setImpact(double value) { - impact = value; + public void setMultiBucketImpact(double value) { + multiBucketImpact = value; } public String getByFieldName() { @@ -533,7 +540,7 @@ public void setInfluencers(List influencers) { @Override public int hashCode() { - return Objects.hash(jobId, detectorIndex, bucketSpan, probability, impact, recordScore, + return Objects.hash(jobId, detectorIndex, bucketSpan, probability, multiBucketImpact, recordScore, initialRecordScore, typical, actual,function, functionDescription, fieldName, byFieldName, byFieldValue, correlatedByFieldValue, partitionFieldName, partitionFieldValue, overFieldName, overFieldValue, timestamp, isInterim, @@ -557,7 +564,7 @@ public boolean equals(Object other) { && this.detectorIndex == that.detectorIndex && this.bucketSpan == that.bucketSpan && this.probability == that.probability - && this.impact == that.impact + && Objects.equals(this.multiBucketImpact, that.multiBucketImpact) && this.recordScore == that.recordScore && this.initialRecordScore == that.initialRecordScore && Objects.deepEquals(this.typical, that.typical) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java index d68a2a1de36a9..8637eb1172281 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/job/results/ReservedFieldNames.java @@ -57,7 +57,7 @@ public final class ReservedFieldNames { AnomalyCause.FIELD_NAME.getPreferredName(), AnomalyRecord.PROBABILITY.getPreferredName(), - AnomalyRecord.IMPACT.getPreferredName(), + AnomalyRecord.MULTI_BUCKET_IMPACT.getPreferredName(), AnomalyRecord.BY_FIELD_NAME.getPreferredName(), AnomalyRecord.BY_FIELD_VALUE.getPreferredName(), AnomalyRecord.CORRELATED_BY_FIELD_VALUE.getPreferredName(), diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java index 1640526bf6495..882a46f3cbe20 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/results/AnomalyRecordTests.java @@ -37,7 +37,9 @@ public AnomalyRecord createTestInstance(String jobId) { anomalyRecord.setActual(Collections.singletonList(randomDouble())); anomalyRecord.setTypical(Collections.singletonList(randomDouble())); anomalyRecord.setProbability(randomDouble()); - anomalyRecord.setImpact(randomDouble()); + if (randomBoolean()) { + anomalyRecord.setMultiBucketImpact(randomDouble()); + } anomalyRecord.setRecordScore(randomDouble()); anomalyRecord.setInitialRecordScore(randomDouble()); anomalyRecord.setInterim(randomBoolean());