From 08a35d44c62475fe41f4c39533f59bff50d542f5 Mon Sep 17 00:00:00 2001 From: Dimitris Athanasiou Date: Tue, 19 Dec 2017 16:28:36 +0000 Subject: [PATCH] [ML] Support multiple rule actions and renames (elastic/x-pack-elasticsearch#3356) Relates elastic/x-pack-elasticsearch#3325 Original commit: elastic/x-pack-elasticsearch@a7f400aeeb925932e4f93e0a3d511b36aa4b2ba1 --- .../xpack/ml/calendars/SpecialEvent.java | 2 +- .../xpack/ml/job/config/DetectionRule.java | 106 ++++++++++-------- .../xpack/ml/job/config/Detector.java | 50 ++++----- .../xpack/ml/job/config/JobUpdate.java | 10 +- .../xpack/ml/job/config/RuleAction.java | 3 +- .../xpack/ml/job/config/RuleCondition.java | 55 +++++---- .../autodetect/writer/FieldConfigWriter.java | 4 +- .../xpack/ml/calendars/SpecialEventTests.java | 9 +- .../ml/integration/DetectionRulesIT.java | 2 +- .../xpack/ml/integration/JobProviderIT.java | 4 +- .../ml/job/config/AnalysisConfigTests.java | 4 +- .../ml/job/config/DetectionRuleTests.java | 50 +++++---- .../xpack/ml/job/config/DetectorTests.java | 32 +++--- .../xpack/ml/job/config/JobUpdateTests.java | 2 +- .../xpack/ml/job/config/RuleActionTests.java | 8 +- .../ml/job/config/RuleConditionTests.java | 26 ++--- .../ControlMsgToProcessWriterTests.java | 14 +-- .../writer/FieldConfigWriterTests.java | 16 ++- .../rest-api-spec/test/ml/filter_crud.yml | 8 +- .../rest-api-spec/test/ml/jobs_crud.yml | 6 +- 20 files changed, 211 insertions(+), 200 deletions(-) diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/calendars/SpecialEvent.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/calendars/SpecialEvent.java index 339ca80351a..f65c33f2c9e 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/calendars/SpecialEvent.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/calendars/SpecialEvent.java @@ -150,7 +150,7 @@ public class SpecialEvent implements ToXContentObject, Writeable { conditions.add(RuleCondition.createTime(Operator.LT, bucketEndTime)); DetectionRule.Builder builder = new DetectionRule.Builder(conditions); - builder.setRuleAction(RuleAction.SKIP_SAMPLING_AND_FILTER_RESULTS); + builder.setActions(RuleAction.FILTER_RESULTS, RuleAction.SKIP_SAMPLING); builder.setConditionsConnective(Connective.AND); return builder.build(); } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/DetectionRule.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/DetectionRule.java index 8b244bc47c7..537593bd8cb 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/DetectionRule.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/DetectionRule.java @@ -21,8 +21,10 @@ import org.elasticsearch.xpack.ml.utils.ExceptionsHelper; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; +import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -32,11 +34,11 @@ import java.util.stream.Collectors; public class DetectionRule implements ToXContentObject, Writeable { public static final ParseField DETECTION_RULE_FIELD = new ParseField("detection_rule"); - public static final ParseField RULE_ACTION_FIELD = new ParseField("rule_action"); + public static final ParseField ACTIONS_FIELD = new ParseField("actions"); public static final ParseField TARGET_FIELD_NAME_FIELD = new ParseField("target_field_name"); public static final ParseField TARGET_FIELD_VALUE_FIELD = new ParseField("target_field_value"); public static final ParseField CONDITIONS_CONNECTIVE_FIELD = new ParseField("conditions_connective"); - public static final ParseField RULE_CONDITIONS_FIELD = new ParseField("rule_conditions"); + public static final ParseField CONDITIONS_FIELD = new ParseField("conditions"); // These parsers follow the pattern that metadata is parsed leniently (to allow for enhancements), whilst config is parsed strictly public static final ObjectParser METADATA_PARSER = @@ -51,12 +53,7 @@ public class DetectionRule implements ToXContentObject, Writeable { for (MlParserType parserType : MlParserType.values()) { ObjectParser parser = PARSERS.get(parserType); assert parser != null; - parser.declareField(Builder::setRuleAction, p -> { - if (p.currentToken() == XContentParser.Token.VALUE_STRING) { - return RuleAction.fromString(p.text()); - } - throw new IllegalArgumentException("Unsupported token [" + p.currentToken() + "]"); - }, RULE_ACTION_FIELD, ValueType.STRING); + parser.declareStringArray(Builder::setActions, ACTIONS_FIELD); parser.declareString(Builder::setTargetFieldName, TARGET_FIELD_NAME_FIELD); parser.declareString(Builder::setTargetFieldValue, TARGET_FIELD_VALUE_FIELD); parser.declareField(Builder::setConditionsConnective, p -> { @@ -65,33 +62,38 @@ public class DetectionRule implements ToXContentObject, Writeable { } throw new IllegalArgumentException("Unsupported token [" + p.currentToken() + "]"); }, CONDITIONS_CONNECTIVE_FIELD, ValueType.STRING); - parser.declareObjectArray(Builder::setRuleConditions, (p, c) -> - RuleCondition.PARSERS.get(parserType).apply(p, c), RULE_CONDITIONS_FIELD); + parser.declareObjectArray(Builder::setConditions, (p, c) -> + RuleCondition.PARSERS.get(parserType).apply(p, c), CONDITIONS_FIELD); } } - private final RuleAction ruleAction; + private final EnumSet actions; private final String targetFieldName; private final String targetFieldValue; private final Connective conditionsConnective; - private final List ruleConditions; + private final List conditions; - private DetectionRule(RuleAction ruleAction, @Nullable String targetFieldName, @Nullable String targetFieldValue, - Connective conditionsConnective, List ruleConditions) { - this.ruleAction = Objects.requireNonNull(ruleAction); + private DetectionRule(EnumSet actions, @Nullable String targetFieldName, @Nullable String targetFieldValue, + Connective conditionsConnective, List conditions) { + this.actions = Objects.requireNonNull(actions); this.targetFieldName = targetFieldName; this.targetFieldValue = targetFieldValue; this.conditionsConnective = Objects.requireNonNull(conditionsConnective); - this.ruleConditions = Collections.unmodifiableList(ruleConditions); + this.conditions = Collections.unmodifiableList(conditions); } public DetectionRule(StreamInput in) throws IOException { - ruleAction = RuleAction.readFromStream(in); + int actionsCount = in.readVInt(); + actions = EnumSet.noneOf(RuleAction.class); + for (int i = 0; i < actionsCount; ++i) { + actions.add(RuleAction.readFromStream(in)); + } + conditionsConnective = Connective.readFromStream(in); int size = in.readVInt(); - ruleConditions = new ArrayList<>(size); + conditions = new ArrayList<>(size); for (int i = 0; i < size; i++) { - ruleConditions.add(new RuleCondition(in)); + conditions.add(new RuleCondition(in)); } targetFieldName = in.readOptionalString(); targetFieldValue = in.readOptionalString(); @@ -99,10 +101,14 @@ public class DetectionRule implements ToXContentObject, Writeable { @Override public void writeTo(StreamOutput out) throws IOException { - ruleAction.writeTo(out); + out.writeVInt(actions.size()); + for (RuleAction action : actions) { + action.writeTo(out); + } + conditionsConnective.writeTo(out); - out.writeVInt(ruleConditions.size()); - for (RuleCondition condition : ruleConditions) { + out.writeVInt(conditions.size()); + for (RuleCondition condition : conditions) { condition.writeTo(out); } out.writeOptionalString(targetFieldName); @@ -112,9 +118,9 @@ public class DetectionRule implements ToXContentObject, Writeable { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - builder.field(RULE_ACTION_FIELD.getPreferredName(), ruleAction); + builder.field(ACTIONS_FIELD.getPreferredName(), actions); builder.field(CONDITIONS_CONNECTIVE_FIELD.getPreferredName(), conditionsConnective); - builder.field(RULE_CONDITIONS_FIELD.getPreferredName(), ruleConditions); + builder.field(CONDITIONS_FIELD.getPreferredName(), conditions); if (targetFieldName != null) { builder.field(TARGET_FIELD_NAME_FIELD.getPreferredName(), targetFieldName); } @@ -125,8 +131,8 @@ public class DetectionRule implements ToXContentObject, Writeable { return builder; } - public RuleAction getRuleAction() { - return ruleAction; + public EnumSet getActions() { + return actions; } @Nullable @@ -143,12 +149,12 @@ public class DetectionRule implements ToXContentObject, Writeable { return conditionsConnective; } - public List getRuleConditions() { - return ruleConditions; + public List getConditions() { + return conditions; } public Set extractReferencedFilters() { - return ruleConditions.stream().map(RuleCondition::getValueFilter).filter(Objects::nonNull).collect(Collectors.toSet()); + return conditions.stream().map(RuleCondition::getFilterId).filter(Objects::nonNull).collect(Collectors.toSet()); } @Override @@ -162,34 +168,46 @@ public class DetectionRule implements ToXContentObject, Writeable { } DetectionRule other = (DetectionRule) obj; - return Objects.equals(ruleAction, other.ruleAction) + return Objects.equals(actions, other.actions) && Objects.equals(targetFieldName, other.targetFieldName) && Objects.equals(targetFieldValue, other.targetFieldValue) && Objects.equals(conditionsConnective, other.conditionsConnective) - && Objects.equals(ruleConditions, other.ruleConditions); + && Objects.equals(conditions, other.conditions); } @Override public int hashCode() { - return Objects.hash(ruleAction, targetFieldName, targetFieldValue, conditionsConnective, ruleConditions); + return Objects.hash(actions, targetFieldName, targetFieldValue, conditionsConnective, conditions); } public static class Builder { - private RuleAction ruleAction = RuleAction.FILTER_RESULTS; + private EnumSet actions = EnumSet.of(RuleAction.FILTER_RESULTS); private String targetFieldName; private String targetFieldValue; private Connective conditionsConnective = Connective.OR; - private List ruleConditions = Collections.emptyList(); + private List conditions = Collections.emptyList(); - public Builder(List ruleConditions) { - this.ruleConditions = ExceptionsHelper.requireNonNull(ruleConditions, RULE_CONDITIONS_FIELD.getPreferredName()); + public Builder(List conditions) { + this.conditions = ExceptionsHelper.requireNonNull(conditions, CONDITIONS_FIELD.getPreferredName()); } private Builder() { } - public Builder setRuleAction(RuleAction ruleAction) { - this.ruleAction = ExceptionsHelper.requireNonNull(ruleAction, RULE_ACTION_FIELD.getPreferredName()); + public Builder setActions(List actions) { + this.actions.clear(); + actions.stream().map(RuleAction::fromString).forEach(this.actions::add); + return this; + } + + public Builder setActions(EnumSet actions) { + this.actions = Objects.requireNonNull(actions, ACTIONS_FIELD.getPreferredName()); + return this; + } + + public Builder setActions(RuleAction... actions) { + this.actions.clear(); + Arrays.stream(actions).forEach(this.actions::add); return this; } @@ -208,8 +226,8 @@ public class DetectionRule implements ToXContentObject, Writeable { return this; } - public Builder setRuleConditions(List ruleConditions) { - this.ruleConditions = ExceptionsHelper.requireNonNull(ruleConditions, RULE_ACTION_FIELD.getPreferredName()); + public Builder setConditions(List conditions) { + this.conditions = ExceptionsHelper.requireNonNull(conditions, CONDITIONS_FIELD.getPreferredName()); return this; } @@ -218,18 +236,18 @@ public class DetectionRule implements ToXContentObject, Writeable { String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_MISSING_TARGET_FIELD_NAME, targetFieldValue); throw ExceptionsHelper.badRequestException(msg); } - if (ruleConditions == null || ruleConditions.isEmpty()) { + if (conditions == null || conditions.isEmpty()) { String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_REQUIRES_AT_LEAST_ONE_CONDITION); throw ExceptionsHelper.badRequestException(msg); } - for (RuleCondition condition : ruleConditions) { - if (condition.getConditionType() == RuleConditionType.CATEGORICAL && targetFieldName != null) { + for (RuleCondition condition : conditions) { + if (condition.getType() == RuleConditionType.CATEGORICAL && targetFieldName != null) { String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_CONDITION_CATEGORICAL_INVALID_OPTION, DetectionRule.TARGET_FIELD_NAME_FIELD.getPreferredName()); throw ExceptionsHelper.badRequestException(msg); } } - return new DetectionRule(ruleAction, targetFieldName, targetFieldValue, conditionsConnective, ruleConditions); + return new DetectionRule(actions, targetFieldName, targetFieldValue, conditionsConnective, conditions); } } } diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/Detector.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/Detector.java index c167e75089a..726fef8c91a 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/Detector.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/Detector.java @@ -83,7 +83,7 @@ public class Detector implements ToXContentObject, Writeable { public static final ParseField PARTITION_FIELD_NAME_FIELD = new ParseField("partition_field_name"); public static final ParseField USE_NULL_FIELD = new ParseField("use_null"); public static final ParseField EXCLUDE_FREQUENT_FIELD = new ParseField("exclude_frequent"); - public static final ParseField DETECTOR_RULES_FIELD = new ParseField("detector_rules"); + public static final ParseField RULES_FIELD = new ParseField("rules"); public static final ParseField DETECTOR_INDEX = new ParseField("detector_index"); // These parsers follow the pattern that metadata is parsed leniently (to allow for enhancements), whilst config is parsed strictly @@ -110,8 +110,8 @@ public class Detector implements ToXContentObject, Writeable { } throw new IllegalArgumentException("Unsupported token [" + p.currentToken() + "]"); }, EXCLUDE_FREQUENT_FIELD, ObjectParser.ValueType.STRING); - parser.declareObjectArray(Builder::setDetectorRules, (p, c) -> - DetectionRule.PARSERS.get(parserType).apply(p, c).build(), DETECTOR_RULES_FIELD); + parser.declareObjectArray(Builder::setRules, (p, c) -> + DetectionRule.PARSERS.get(parserType).apply(p, c).build(), RULES_FIELD); parser.declareInt(Builder::setDetectorIndex, DETECTOR_INDEX); } } @@ -329,7 +329,7 @@ public class Detector implements ToXContentObject, Writeable { private final String partitionFieldName; private final boolean useNull; private final ExcludeFrequent excludeFrequent; - private final List detectorRules; + private final List rules; private final int detectorIndex; public Detector(StreamInput in) throws IOException { @@ -341,7 +341,7 @@ public class Detector implements ToXContentObject, Writeable { partitionFieldName = in.readOptionalString(); useNull = in.readBoolean(); excludeFrequent = in.readBoolean() ? ExcludeFrequent.readFromStream(in) : null; - detectorRules = in.readList(DetectionRule::new); + rules = in.readList(DetectionRule::new); if (in.getVersion().onOrAfter(Version.V_5_5_0)) { detectorIndex = in.readInt(); } else { @@ -365,7 +365,7 @@ public class Detector implements ToXContentObject, Writeable { } else { out.writeBoolean(false); } - out.writeList(detectorRules); + out.writeList(rules); if (out.getVersion().onOrAfter(Version.V_5_5_0)) { out.writeInt(detectorIndex); } @@ -394,7 +394,7 @@ public class Detector implements ToXContentObject, Writeable { if (excludeFrequent != null) { builder.field(EXCLUDE_FREQUENT_FIELD.getPreferredName(), excludeFrequent); } - builder.field(DETECTOR_RULES_FIELD.getPreferredName(), detectorRules); + builder.field(RULES_FIELD.getPreferredName(), rules); // negative means "unknown", which should only happen for a 5.4 job if (detectorIndex >= 0 // no point writing this to cluster state, as the indexes will get reassigned on reload anyway @@ -406,7 +406,7 @@ public class Detector implements ToXContentObject, Writeable { } private Detector(String detectorDescription, String function, String fieldName, String byFieldName, String overFieldName, - String partitionFieldName, boolean useNull, ExcludeFrequent excludeFrequent, List detectorRules, + String partitionFieldName, boolean useNull, ExcludeFrequent excludeFrequent, List rules, int detectorIndex) { this.function = function; this.fieldName = fieldName; @@ -415,7 +415,7 @@ public class Detector implements ToXContentObject, Writeable { this.partitionFieldName = partitionFieldName; this.useNull = useNull; this.excludeFrequent = excludeFrequent; - this.detectorRules = Collections.unmodifiableList(detectorRules); + this.rules = Collections.unmodifiableList(rules); this.detectorDescription = detectorDescription != null ? detectorDescription : DefaultDetectorDescription.of(this); this.detectorIndex = detectorIndex; } @@ -491,8 +491,8 @@ public class Detector implements ToXContentObject, Writeable { return excludeFrequent; } - public List getDetectorRules() { - return detectorRules; + public List getRules() { + return rules; } /** @@ -514,8 +514,8 @@ public class Detector implements ToXContentObject, Writeable { } public Set extractReferencedFilters() { - return detectorRules == null ? Collections.emptySet() - : detectorRules.stream().map(DetectionRule::extractReferencedFilters) + return rules == null ? Collections.emptySet() + : rules.stream().map(DetectionRule::extractReferencedFilters) .flatMap(Set::stream).collect(Collectors.toSet()); } @@ -556,15 +556,14 @@ public class Detector implements ToXContentObject, Writeable { Objects.equals(this.partitionFieldName, that.partitionFieldName) && Objects.equals(this.useNull, that.useNull) && Objects.equals(this.excludeFrequent, that.excludeFrequent) && - Objects.equals(this.detectorRules, that.detectorRules) && + Objects.equals(this.rules, that.rules) && this.detectorIndex == that.detectorIndex; } @Override public int hashCode() { - return Objects.hash(detectorDescription, function, fieldName, byFieldName, - overFieldName, partitionFieldName, useNull, excludeFrequent, - detectorRules, detectorIndex); + return Objects.hash(detectorDescription, function, fieldName, byFieldName, overFieldName, partitionFieldName, useNull, + excludeFrequent, rules, detectorIndex); } public static class Builder { @@ -587,7 +586,7 @@ public class Detector implements ToXContentObject, Writeable { private String partitionFieldName; private boolean useNull = false; private ExcludeFrequent excludeFrequent; - private List detectorRules = Collections.emptyList(); + private List rules = Collections.emptyList(); // negative means unknown, and is expected for v5.4 jobs private int detectorIndex = -1; @@ -603,8 +602,7 @@ public class Detector implements ToXContentObject, Writeable { partitionFieldName = detector.partitionFieldName; useNull = detector.useNull; excludeFrequent = detector.excludeFrequent; - detectorRules = new ArrayList<>(detector.detectorRules.size()); - detectorRules.addAll(detector.getDetectorRules()); + rules = new ArrayList<>(detector.getRules()); detectorIndex = detector.detectorIndex; } @@ -645,8 +643,8 @@ public class Detector implements ToXContentObject, Writeable { this.excludeFrequent = excludeFrequent; } - public void setDetectorRules(List detectorRules) { - this.detectorRules = detectorRules; + public void setRules(List rules) { + this.rules = rules; } public void setDetectorIndex(int detectorIndex) { @@ -704,12 +702,12 @@ public class Detector implements ToXContentObject, Writeable { } String function = this.function == null ? Detector.METRIC : this.function; - if (detectorRules.isEmpty() == false) { + if (rules.isEmpty() == false) { if (FUNCTIONS_WITHOUT_RULE_SUPPORT.contains(function)) { String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_NOT_SUPPORTED_BY_FUNCTION, function); throw ExceptionsHelper.badRequestException(msg); } - for (DetectionRule rule : detectorRules) { + for (DetectionRule rule : rules) { checkScoping(rule); } } @@ -764,7 +762,7 @@ public class Detector implements ToXContentObject, Writeable { } return new Detector(detectorDescription, function, fieldName, byFieldName, overFieldName, partitionFieldName, - useNull, excludeFrequent, detectorRules, detectorIndex); + useNull, excludeFrequent, rules, detectorIndex); } public List extractAnalysisFields() { @@ -802,7 +800,7 @@ public class Detector implements ToXContentObject, Writeable { String targetFieldName = rule.getTargetFieldName(); checkTargetFieldNameIsValid(extractAnalysisFields(), targetFieldName); List validOptions = getValidFieldNameOptions(rule); - for (RuleCondition condition : rule.getRuleConditions()) { + for (RuleCondition condition : rule.getConditions()) { if (!validOptions.contains(condition.getFieldName())) { String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_CONDITION_INVALID_FIELD_NAME, validOptions, condition.getFieldName()); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/JobUpdate.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/JobUpdate.java index dc304149769..85096c49a34 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/JobUpdate.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/JobUpdate.java @@ -315,7 +315,7 @@ public class JobUpdate implements Writeable, ToXContentObject { detectorbuilder.setDetectorDescription(dd.getDescription()); } if (dd.getRules() != null) { - detectorbuilder.setDetectorRules(dd.getRules()); + detectorbuilder.setRules(dd.getRules()); } ac.getDetectors().set(dd.getDetectorIndex(), detectorbuilder.build()); } @@ -435,13 +435,11 @@ public class JobUpdate implements Writeable, ToXContentObject { new ConstructingObjectParser<>("detector_update", a -> new DetectorUpdate((int) a[0], (String) a[1], (List) a[2])); - public static final ParseField RULES = new ParseField("rules"); - static { PARSER.declareInt(ConstructingObjectParser.optionalConstructorArg(), Detector.DETECTOR_INDEX); PARSER.declareStringOrNull(ConstructingObjectParser.optionalConstructorArg(), Job.DESCRIPTION); - PARSER.declareObjectArray(ConstructingObjectParser.optionalConstructorArg(), - (parser, parseFieldMatcher) -> DetectionRule.CONFIG_PARSER.apply(parser, parseFieldMatcher).build(), RULES); + PARSER.declareObjectArray(ConstructingObjectParser.optionalConstructorArg(), (parser, parseFieldMatcher) -> + DetectionRule.CONFIG_PARSER.apply(parser, parseFieldMatcher).build(), Detector.RULES_FIELD); } private int detectorIndex; @@ -495,7 +493,7 @@ public class JobUpdate implements Writeable, ToXContentObject { builder.field(Job.DESCRIPTION.getPreferredName(), description); } if (rules != null) { - builder.field(RULES.getPreferredName(), rules); + builder.field(Detector.RULES_FIELD.getPreferredName(), rules); } builder.endObject(); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleAction.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleAction.java index 20efbf01ac6..2a96cc45c4a 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleAction.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleAction.java @@ -14,8 +14,7 @@ import java.util.Locale; public enum RuleAction implements Writeable { FILTER_RESULTS, - SKIP_SAMPLING, - SKIP_SAMPLING_AND_FILTER_RESULTS; + SKIP_SAMPLING; /** * Case-insensitive from string method. diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleCondition.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleCondition.java index b23ed163066..a950189931f 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleCondition.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/config/RuleCondition.java @@ -26,11 +26,10 @@ import java.util.Map; import java.util.Objects; public class RuleCondition implements ToXContentObject, Writeable { - public static final ParseField CONDITION_TYPE_FIELD = new ParseField("condition_type"); + public static final ParseField TYPE_FIELD = new ParseField("type"); public static final ParseField RULE_CONDITION_FIELD = new ParseField("rule_condition"); public static final ParseField FIELD_NAME_FIELD = new ParseField("field_name"); public static final ParseField FIELD_VALUE_FIELD = new ParseField("field_value"); - public static final ParseField VALUE_FILTER_FIELD = new ParseField("value_filter"); // These parsers follow the pattern that metadata is parsed leniently (to allow for enhancements), whilst config is parsed strictly public static final ConstructingObjectParser METADATA_PARSER = @@ -53,60 +52,60 @@ public class RuleCondition implements ToXContentObject, Writeable { return RuleConditionType.fromString(p.text()); } throw new IllegalArgumentException("Unsupported token [" + p.currentToken() + "]"); - }, CONDITION_TYPE_FIELD, ValueType.STRING); + }, TYPE_FIELD, ValueType.STRING); parser.declareStringOrNull(ConstructingObjectParser.optionalConstructorArg(), FIELD_NAME_FIELD); parser.declareStringOrNull(ConstructingObjectParser.optionalConstructorArg(), FIELD_VALUE_FIELD); parser.declareObject(ConstructingObjectParser.optionalConstructorArg(), Condition.PARSER, Condition.CONDITION_FIELD); - parser.declareStringOrNull(ConstructingObjectParser.optionalConstructorArg(), VALUE_FILTER_FIELD); + parser.declareStringOrNull(ConstructingObjectParser.optionalConstructorArg(), MlFilter.ID); } } - private final RuleConditionType conditionType; + private final RuleConditionType type; private final String fieldName; private final String fieldValue; private final Condition condition; - private final String valueFilter; + private final String filterId; public RuleCondition(StreamInput in) throws IOException { - conditionType = RuleConditionType.readFromStream(in); + type = RuleConditionType.readFromStream(in); condition = in.readOptionalWriteable(Condition::new); fieldName = in.readOptionalString(); fieldValue = in.readOptionalString(); - valueFilter = in.readOptionalString(); + filterId = in.readOptionalString(); } @Override public void writeTo(StreamOutput out) throws IOException { - conditionType.writeTo(out); + type.writeTo(out); out.writeOptionalWriteable(condition); out.writeOptionalString(fieldName); out.writeOptionalString(fieldValue); - out.writeOptionalString(valueFilter); + out.writeOptionalString(filterId); } - RuleCondition(RuleConditionType conditionType, String fieldName, String fieldValue, Condition condition, String valueFilter) { - this.conditionType = conditionType; + RuleCondition(RuleConditionType type, String fieldName, String fieldValue, Condition condition, String filterId) { + this.type = type; this.fieldName = fieldName; this.fieldValue = fieldValue; this.condition = condition; - this.valueFilter = valueFilter; + this.filterId = filterId; verifyFieldsBoundToType(this); verifyFieldValueRequiresFieldName(this); } public RuleCondition(RuleCondition ruleCondition) { - this.conditionType = ruleCondition.conditionType; + this.type = ruleCondition.type; this.fieldName = ruleCondition.fieldName; this.fieldValue = ruleCondition.fieldValue; this.condition = ruleCondition.condition; - this.valueFilter = ruleCondition.valueFilter; + this.filterId = ruleCondition.filterId; } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); - builder.field(CONDITION_TYPE_FIELD.getPreferredName(), conditionType); + builder.field(TYPE_FIELD.getPreferredName(), type); if (condition != null) { builder.field(Condition.CONDITION_FIELD.getPreferredName(), condition); } @@ -116,15 +115,15 @@ public class RuleCondition implements ToXContentObject, Writeable { if (fieldValue != null) { builder.field(FIELD_VALUE_FIELD.getPreferredName(), fieldValue); } - if (valueFilter != null) { - builder.field(VALUE_FILTER_FIELD.getPreferredName(), valueFilter); + if (filterId != null) { + builder.field(MlFilter.ID.getPreferredName(), filterId); } builder.endObject(); return builder; } - public RuleConditionType getConditionType() { - return conditionType; + public RuleConditionType getType() { + return type; } /** @@ -153,8 +152,8 @@ public class RuleCondition implements ToXContentObject, Writeable { * The unique identifier of a filter. Required when the rule type is * categorical. Should be null for all other types. */ - public String getValueFilter() { - return valueFilter; + public String getFilterId() { + return filterId; } @Override @@ -168,14 +167,14 @@ public class RuleCondition implements ToXContentObject, Writeable { } RuleCondition other = (RuleCondition) obj; - return Objects.equals(conditionType, other.conditionType) && Objects.equals(fieldName, other.fieldName) + return Objects.equals(type, other.type) && Objects.equals(fieldName, other.fieldName) && Objects.equals(fieldValue, other.fieldValue) && Objects.equals(condition, other.condition) - && Objects.equals(valueFilter, other.valueFilter); + && Objects.equals(filterId, other.filterId); } @Override public int hashCode() { - return Objects.hash(conditionType, fieldName, fieldValue, condition, valueFilter); + return Objects.hash(type, fieldName, fieldValue, condition, filterId); } public static RuleCondition createCategorical(String fieldName, String valueFilter) { @@ -195,7 +194,7 @@ public class RuleCondition implements ToXContentObject, Writeable { } private static void verifyFieldsBoundToType(RuleCondition ruleCondition) throws ElasticsearchParseException { - switch (ruleCondition.getConditionType()) { + switch (ruleCondition.getType()) { case CATEGORICAL: verifyCategorical(ruleCondition); break; @@ -215,7 +214,7 @@ public class RuleCondition implements ToXContentObject, Writeable { private static void verifyCategorical(RuleCondition ruleCondition) throws ElasticsearchParseException { checkCategoricalHasNoField(Condition.CONDITION_FIELD.getPreferredName(), ruleCondition.getCondition()); checkCategoricalHasNoField(RuleCondition.FIELD_VALUE_FIELD.getPreferredName(), ruleCondition.getFieldValue()); - checkCategoricalHasField(RuleCondition.VALUE_FILTER_FIELD.getPreferredName(), ruleCondition.getValueFilter()); + checkCategoricalHasField(MlFilter.ID.getPreferredName(), ruleCondition.getFilterId()); } private static void checkCategoricalHasNoField(String fieldName, Object fieldValue) throws ElasticsearchParseException { @@ -233,7 +232,7 @@ public class RuleCondition implements ToXContentObject, Writeable { } private static void verifyNumerical(RuleCondition ruleCondition) throws ElasticsearchParseException { - checkNumericalHasNoField(RuleCondition.VALUE_FILTER_FIELD.getPreferredName(), ruleCondition.getValueFilter()); + checkNumericalHasNoField(MlFilter.ID.getPreferredName(), ruleCondition.getFilterId()); checkNumericalHasField(Condition.CONDITION_FIELD.getPreferredName(), ruleCondition.getCondition()); if (ruleCondition.getFieldName() != null && ruleCondition.getFieldValue() == null) { String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_CONDITION_NUMERICAL_WITH_FIELD_NAME_REQUIRES_FIELD_VALUE); diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/writer/FieldConfigWriter.java b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/writer/FieldConfigWriter.java index 3d107d39ff1..c25635478dc 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/writer/FieldConfigWriter.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ml/job/process/autodetect/writer/FieldConfigWriter.java @@ -107,8 +107,8 @@ public class FieldConfigWriter { StringBuilder contents) throws IOException { List rules = new ArrayList<>(); - if (detector.getDetectorRules() != null) { - rules.addAll(detector.getDetectorRules()); + if (detector.getRules() != null) { + rules.addAll(detector.getRules()); } rules.addAll(specialEvents); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/calendars/SpecialEventTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/calendars/SpecialEventTests.java index 148b6200d78..6ecd8496ac8 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/calendars/SpecialEventTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/calendars/SpecialEventTests.java @@ -22,6 +22,7 @@ import java.time.Instant; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; public class SpecialEventTests extends AbstractSerializingTestCase { @@ -60,14 +61,14 @@ public class SpecialEventTests extends AbstractSerializingTestCase DetectionRule rule = event.toDetectionRule(TimeValue.timeValueSeconds(bucketSpanSecs)); assertEquals(Connective.AND, rule.getConditionsConnective()); - assertEquals(RuleAction.SKIP_SAMPLING_AND_FILTER_RESULTS, rule.getRuleAction()); + assertEquals(rule.getActions(), EnumSet.of(RuleAction.FILTER_RESULTS, RuleAction.SKIP_SAMPLING)); assertNull(rule.getTargetFieldName()); assertNull(rule.getTargetFieldValue()); - List conditions = rule.getRuleConditions(); + List conditions = rule.getConditions(); assertEquals(2, conditions.size()); - assertEquals(RuleConditionType.TIME, conditions.get(0).getConditionType()); - assertEquals(RuleConditionType.TIME, conditions.get(1).getConditionType()); + assertEquals(RuleConditionType.TIME, conditions.get(0).getType()); + assertEquals(RuleConditionType.TIME, conditions.get(1).getType()); assertEquals(Operator.GTE, conditions.get(0).getCondition().getOperator()); assertEquals(Operator.LT, conditions.get(1).getCondition().getOperator()); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/DetectionRulesIT.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/DetectionRulesIT.java index d22b34e5369..0933f8780f4 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/DetectionRulesIT.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/DetectionRulesIT.java @@ -61,7 +61,7 @@ public class DetectionRulesIT extends MlNativeAutodetectIntegTestCase { DetectionRule rule = new DetectionRule.Builder(Arrays.asList(condition1, condition2, condition3)).build(); Detector.Builder detector = new Detector.Builder("max", "value"); - detector.setDetectorRules(Arrays.asList(rule)); + detector.setRules(Arrays.asList(rule)); detector.setByFieldName("by_field"); AnalysisConfig.Builder analysisConfig = new AnalysisConfig.Builder( diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/JobProviderIT.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/JobProviderIT.java index 724efa2ab46..850ea920857 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/JobProviderIT.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/integration/JobProviderIT.java @@ -431,10 +431,10 @@ public class JobProviderIT extends XPackSingleNodeTestCase { } DetectionRule.Builder rule = new DetectionRule.Builder(conditions) - .setRuleAction(RuleAction.FILTER_RESULTS) + .setActions(RuleAction.FILTER_RESULTS) .setConditionsConnective(Connective.OR); - detector.setDetectorRules(Collections.singletonList(rule.build())); + detector.setRules(Collections.singletonList(rule.build())); } return new AnalysisConfig.Builder(Collections.singletonList(detector.build())); diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/AnalysisConfigTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/AnalysisConfigTests.java index 5ebdc4f86ce..16c9242f9d7 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/AnalysisConfigTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/AnalysisConfigTests.java @@ -461,9 +461,9 @@ public class AnalysisConfigTests extends AbstractSerializingTestCase ruleConditions = new ArrayList<>(size); for (int i = 0; i < size; i++) { // no need for random condition (it is already tested) ruleConditions.addAll(createRule(Double.toString(randomDouble()))); } - return new DetectionRule.Builder(ruleConditions) - .setRuleAction(ruleAction) - .setTargetFieldName(targetFieldName) - .setTargetFieldValue(targetFieldValue) - .setConditionsConnective(connective) - .build(); + DetectionRule.Builder builder = new DetectionRule.Builder(ruleConditions); + + if (randomBoolean()) { + EnumSet actions = EnumSet.noneOf(RuleAction.class); + int actionsCount = randomIntBetween(1, RuleAction.values().length); + for (int i = 0; i < actionsCount; ++i) { + actions.add(randomFrom(RuleAction.values())); + } + builder.setActions(actions); + } + + if (randomBoolean()) { + builder.setConditionsConnective(randomFrom(Connective.values())); + } + + if (randomBoolean()) { + builder.setTargetFieldName(randomAlphaOfLengthBetween(1, 20)); + builder.setTargetFieldValue(randomAlphaOfLengthBetween(1, 20)); + } + + return builder.build(); } @Override @@ -125,16 +133,16 @@ public class DetectionRuleTests extends AbstractSerializingTestCase ruleConditions = instance.getRuleConditions(); - RuleAction ruleAction = instance.getRuleAction(); + List conditions = instance.getConditions(); + EnumSet actions = instance.getActions(); String targetFieldName = instance.getTargetFieldName(); String targetFieldValue = instance.getTargetFieldValue(); Connective connective = instance.getConditionsConnective(); switch (between(0, 3)) { case 0: - ruleConditions = new ArrayList<>(ruleConditions); - ruleConditions.addAll(createRule(Double.toString(randomDouble()))); + conditions = new ArrayList<>(conditions); + conditions.addAll(createRule(Double.toString(randomDouble()))); break; case 1: targetFieldName = randomAlphaOfLengthBetween(5, 10); @@ -156,7 +164,7 @@ public class DetectionRuleTests extends AbstractSerializingTestCase { Condition condition = new Condition(Operator.GT, "5"); DetectionRule rule = new DetectionRule.Builder( Collections.singletonList(new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, "by2", "val", condition, null))) - .setRuleAction(RuleAction.FILTER_RESULTS).setTargetFieldName("over_field") + .setActions(RuleAction.FILTER_RESULTS).setTargetFieldName("over_field") .setTargetFieldValue("targetValue") .setConditionsConnective(Connective.AND) .build(); - builder.setDetectorRules(Collections.singletonList(rule)); + builder.setRules(Collections.singletonList(rule)); detector2 = builder.build(); assertFalse(detector1.equals(detector2)); } @@ -84,22 +84,22 @@ public class DetectorTests extends AbstractSerializingTestCase { Condition condition = new Condition(Operator.GT, "5"); DetectionRule rule = new DetectionRule.Builder( Collections.singletonList(new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, null, null, condition, null))) - .setRuleAction(RuleAction.FILTER_RESULTS) + .setActions(RuleAction.FILTER_RESULTS) .setTargetFieldName("over_field") .setTargetFieldValue("targetValue") .setConditionsConnective(Connective.AND) .build(); - builder.setDetectorRules(Collections.singletonList(rule)); + builder.setRules(Collections.singletonList(rule)); builder.setByFieldName(null); detector = builder.build(); assertEquals(Collections.singletonList("over_field"), detector.extractAnalysisFields()); builder = new Detector.Builder(detector); rule = new DetectionRule.Builder( Collections.singletonList(new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, null, null, condition, null))) - .setRuleAction(RuleAction.FILTER_RESULTS) + .setActions(RuleAction.FILTER_RESULTS) .setConditionsConnective(Connective.AND) .build(); - builder.setDetectorRules(Collections.singletonList(rule)); + builder.setRules(Collections.singletonList(rule)); builder.setOverFieldName(null); detector = builder.build(); assertTrue(detector.extractAnalysisFields().isEmpty()); @@ -107,7 +107,7 @@ public class DetectorTests extends AbstractSerializingTestCase { public void testExtractReferencedLists() { Detector.Builder builder = createDetector(); - builder.setDetectorRules(Arrays.asList( + builder.setRules(Arrays.asList( new DetectionRule.Builder(Collections.singletonList(RuleCondition.createCategorical("by_field", "list1"))).build(), new DetectionRule.Builder(Collections.singletonList(RuleCondition.createCategorical("by_field", "list2"))).build())); @@ -140,12 +140,12 @@ public class DetectorTests extends AbstractSerializingTestCase { Condition condition = new Condition(Operator.GT, "5"); DetectionRule rule = new DetectionRule.Builder( Collections.singletonList(new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, "by_field", "val", condition, null))) - .setRuleAction(RuleAction.FILTER_RESULTS) + .setActions(RuleAction.FILTER_RESULTS) .setTargetFieldName("over_field") .setTargetFieldValue("targetValue") .setConditionsConnective(Connective.AND) .build(); - detector.setDetectorRules(Collections.singletonList(rule)); + detector.setRules(Collections.singletonList(rule)); return detector; } @@ -176,15 +176,15 @@ public class DetectorTests extends AbstractSerializingTestCase { } if (randomBoolean()) { int size = randomInt(10); - List detectorRules = new ArrayList<>(size); + List rules = new ArrayList<>(size); for (int i = 0; i < size; i++) { // no need for random DetectionRule (it is already tested) Condition condition = new Condition(Operator.GT, "5"); - detectorRules.add(new DetectionRule.Builder( + rules.add(new DetectionRule.Builder( Collections.singletonList(new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, null, null, condition, null))) .setTargetFieldName(fieldName).build()); } - detector.setDetectorRules(detectorRules); + detector.setRules(rules); } if (randomBoolean()) { detector.setUseNull(randomBoolean()); @@ -508,14 +508,14 @@ public class DetectorTests extends AbstractSerializingTestCase { } } - public void testVerify_GivenInvalidDetectionRuleTargetFieldName() { + public void testVerify_GivenInvalidRuleTargetFieldName() { Detector.Builder detector = new Detector.Builder("mean", "metricVale"); detector.setByFieldName("metricName"); detector.setPartitionFieldName("instance"); RuleCondition ruleCondition = new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, "metricName", "metricVale", new Condition(Operator.LT, "5"), null); DetectionRule rule = new DetectionRule.Builder(Collections.singletonList(ruleCondition)).setTargetFieldName("instancE").build(); - detector.setDetectorRules(Collections.singletonList(rule)); + detector.setRules(Collections.singletonList(rule)); ElasticsearchException e = ESTestCase.expectThrows(ElasticsearchException.class, detector::build); @@ -524,14 +524,14 @@ public class DetectorTests extends AbstractSerializingTestCase { e.getMessage()); } - public void testVerify_GivenValidDetectionRule() { + public void testVerify_GivenValidRule() { Detector.Builder detector = new Detector.Builder("mean", "metricVale"); detector.setByFieldName("metricName"); detector.setPartitionFieldName("instance"); RuleCondition ruleCondition = new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, "metricName", "CPU", new Condition(Operator.LT, "5"), null); DetectionRule rule = new DetectionRule.Builder(Collections.singletonList(ruleCondition)).setTargetFieldName("instance").build(); - detector.setDetectorRules(Collections.singletonList(rule)); + detector.setRules(Collections.singletonList(rule)); detector.build(); } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/JobUpdateTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/JobUpdateTests.java index fa03921f282..7ce8e74ef23 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/JobUpdateTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/JobUpdateTests.java @@ -165,7 +165,7 @@ public class JobUpdateTests extends AbstractSerializingTestCase { updatedJob.getAnalysisConfig().getDetectors().get(detectorUpdate.getDetectorIndex()).getDetectorDescription()); assertNotNull(updatedJob.getAnalysisConfig().getDetectors().get(detectorUpdate.getDetectorIndex()).getDetectorDescription()); assertEquals(detectorUpdate.getRules(), - updatedJob.getAnalysisConfig().getDetectors().get(detectorUpdate.getDetectorIndex()).getDetectorRules()); + updatedJob.getAnalysisConfig().getDetectors().get(detectorUpdate.getDetectorIndex()).getRules()); } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleActionTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleActionTests.java index f46bf5a2482..b371471227a 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleActionTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleActionTests.java @@ -11,14 +11,12 @@ import org.elasticsearch.test.ESTestCase; import static org.hamcrest.Matchers.equalTo; -public class -RuleActionTests extends ESTestCase { +public class RuleActionTests extends ESTestCase { public void testForString() { assertEquals(RuleAction.FILTER_RESULTS, RuleAction.fromString("filter_results")); assertEquals(RuleAction.FILTER_RESULTS, RuleAction.fromString("FILTER_RESULTS")); assertEquals(RuleAction.SKIP_SAMPLING, RuleAction.fromString("SKip_sampLing")); - assertEquals(RuleAction.SKIP_SAMPLING_AND_FILTER_RESULTS, RuleAction.fromString("skip_sampling_and_filter_results")); } public void testToString() { @@ -34,9 +32,9 @@ RuleActionTests extends ESTestCase { } try (BytesStreamOutput out = new BytesStreamOutput()) { - out.writeVInt(2); + out.writeVInt(1); try (StreamInput in = out.bytes().streamInput()) { - assertThat(RuleAction.readFromStream(in), equalTo(RuleAction.SKIP_SAMPLING_AND_FILTER_RESULTS)); + assertThat(RuleAction.readFromStream(in), equalTo(RuleAction.SKIP_SAMPLING)); } } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleConditionTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleConditionTests.java index 0a38319e169..84e8e2face9 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleConditionTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ml/job/config/RuleConditionTests.java @@ -52,7 +52,7 @@ public class RuleConditionTests extends AbstractSerializingTestCase new RuleCondition(RuleConditionType.CATEGORICAL, null, null, null, null)); - assertEquals("Invalid detector rule: a categorical rule_condition requires value_filter to be set", e.getMessage()); + assertEquals("Invalid detector rule: a categorical rule_condition requires filter_id to be set", e.getMessage()); } - public void testVerify_GivenNumericalActualWithValueFilter() { + public void testVerify_GivenNumericalActualWithFilterId() { ElasticsearchException e = expectThrows(ElasticsearchException.class, () -> new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, null, null, null, "myFilter")); - assertEquals("Invalid detector rule: a numerical rule_condition does not support value_filter", e.getMessage()); + assertEquals("Invalid detector rule: a numerical rule_condition does not support filter_id", e.getMessage()); } public void testVerify_GivenNumericalActualWithoutCondition() { @@ -146,10 +146,10 @@ public class RuleConditionTests extends AbstractSerializingTestCase new RuleCondition(RuleConditionType.NUMERICAL_ACTUAL, null, null, null, "myFilter")); - assertEquals("Invalid detector rule: a numerical rule_condition does not support value_filter", e.getMessage()); + assertEquals("Invalid detector rule: a numerical rule_condition does not support filter_id", e.getMessage()); } public void testVerify_GivenNumericalTypicalWithoutCondition() { @@ -158,10 +158,10 @@ public class RuleConditionTests extends AbstractSerializingTestCase new RuleCondition(RuleConditionType.NUMERICAL_DIFF_ABS, null, null, null, "myFilter")); - assertEquals("Invalid detector rule: a numerical rule_condition does not support value_filter", e.getMessage()); + assertEquals("Invalid detector rule: a numerical rule_condition does not support filter_id", e.getMessage()); } public void testVerify_GivenNumericalDiffAbsWithoutCondition() { @@ -220,12 +220,12 @@ public class RuleConditionTests extends AbstractSerializingTestCase