[ML] Add categorical exclude condition (elastic/x-pack-elasticsearch#4326)
Original commit: elastic/x-pack-elasticsearch@6c80988e08
This commit is contained in:
parent
411f683521
commit
7e4e1dabcf
|
@ -251,7 +251,7 @@ public class DetectionRule implements ToXContentObject, Writeable {
|
||||||
throw ExceptionsHelper.badRequestException(msg);
|
throw ExceptionsHelper.badRequestException(msg);
|
||||||
}
|
}
|
||||||
for (RuleCondition condition : conditions) {
|
for (RuleCondition condition : conditions) {
|
||||||
if (condition.getType() == RuleConditionType.CATEGORICAL && targetFieldName != null) {
|
if (condition.getType().isCategorical() && targetFieldName != null) {
|
||||||
String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_CONDITION_CATEGORICAL_INVALID_OPTION,
|
String msg = Messages.getMessage(Messages.JOB_CONFIG_DETECTION_RULE_CONDITION_CATEGORICAL_INVALID_OPTION,
|
||||||
DetectionRule.TARGET_FIELD_NAME_FIELD.getPreferredName());
|
DetectionRule.TARGET_FIELD_NAME_FIELD.getPreferredName());
|
||||||
throw ExceptionsHelper.badRequestException(msg);
|
throw ExceptionsHelper.badRequestException(msg);
|
||||||
|
|
|
@ -698,6 +698,7 @@ public class Detector implements ToXContentObject, Writeable {
|
||||||
List<String> validOptions = Collections.emptyList();
|
List<String> validOptions = Collections.emptyList();
|
||||||
switch (condition.getType()) {
|
switch (condition.getType()) {
|
||||||
case CATEGORICAL:
|
case CATEGORICAL:
|
||||||
|
case CATEGORICAL_COMPLEMENT:
|
||||||
validOptions = extractAnalysisFields();
|
validOptions = extractAnalysisFields();
|
||||||
break;
|
break;
|
||||||
case NUMERICAL_ACTUAL:
|
case NUMERICAL_ACTUAL:
|
||||||
|
|
|
@ -197,6 +197,7 @@ public class RuleCondition implements ToXContentObject, Writeable {
|
||||||
private static void verifyFieldsBoundToType(RuleCondition ruleCondition) throws ElasticsearchParseException {
|
private static void verifyFieldsBoundToType(RuleCondition ruleCondition) throws ElasticsearchParseException {
|
||||||
switch (ruleCondition.getType()) {
|
switch (ruleCondition.getType()) {
|
||||||
case CATEGORICAL:
|
case CATEGORICAL:
|
||||||
|
case CATEGORICAL_COMPLEMENT:
|
||||||
verifyCategorical(ruleCondition);
|
verifyCategorical(ruleCondition);
|
||||||
break;
|
break;
|
||||||
case NUMERICAL_ACTUAL:
|
case NUMERICAL_ACTUAL:
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
package org.elasticsearch.xpack.core.ml.job.config;
|
package org.elasticsearch.xpack.core.ml.job.config;
|
||||||
|
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
@ -14,22 +15,29 @@ import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public enum RuleConditionType implements Writeable {
|
public enum RuleConditionType implements Writeable {
|
||||||
CATEGORICAL(false),
|
CATEGORICAL(false, true),
|
||||||
NUMERICAL_ACTUAL(true),
|
NUMERICAL_ACTUAL(true, false),
|
||||||
NUMERICAL_TYPICAL(true),
|
NUMERICAL_TYPICAL(true, false),
|
||||||
NUMERICAL_DIFF_ABS(true),
|
NUMERICAL_DIFF_ABS(true, false),
|
||||||
TIME(false);
|
TIME(false, false),
|
||||||
|
CATEGORICAL_COMPLEMENT(false, true);
|
||||||
|
|
||||||
private final boolean isNumerical;
|
private final boolean isNumerical;
|
||||||
|
private final boolean isCategorical;
|
||||||
|
|
||||||
RuleConditionType(boolean isNumerical) {
|
RuleConditionType(boolean isNumerical, boolean isCategorical) {
|
||||||
this.isNumerical = isNumerical;
|
this.isNumerical = isNumerical;
|
||||||
|
this.isCategorical = isCategorical;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNumerical() {
|
public boolean isNumerical() {
|
||||||
return isNumerical;
|
return isNumerical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCategorical() {
|
||||||
|
return isCategorical;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Case-insensitive from string method.
|
* Case-insensitive from string method.
|
||||||
*
|
*
|
||||||
|
@ -47,7 +55,11 @@ public enum RuleConditionType implements Writeable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
out.writeEnum(this);
|
if (this == CATEGORICAL_COMPLEMENT && out.getVersion().before(Version.V_6_3_0)) {
|
||||||
|
out.writeEnum(CATEGORICAL);
|
||||||
|
} else {
|
||||||
|
out.writeEnum(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,25 +19,22 @@ public class RuleConditionTests extends AbstractSerializingTestCase<RuleConditio
|
||||||
String fieldName = null;
|
String fieldName = null;
|
||||||
String valueFilter = null;
|
String valueFilter = null;
|
||||||
String fieldValue = null;
|
String fieldValue = null;
|
||||||
RuleConditionType r = randomFrom(RuleConditionType.values());
|
RuleConditionType type = randomFrom(RuleConditionType.values());
|
||||||
switch (r) {
|
if (type.isCategorical()) {
|
||||||
case CATEGORICAL:
|
|
||||||
valueFilter = randomAlphaOfLengthBetween(1, 20);
|
valueFilter = randomAlphaOfLengthBetween(1, 20);
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
fieldName = randomAlphaOfLengthBetween(1, 20);
|
fieldName = randomAlphaOfLengthBetween(1, 20);
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
default:
|
// no need to randomize, it is properly randomly tested in
|
||||||
// no need to randomize, it is properly randomily tested in
|
|
||||||
// ConditionTest
|
// ConditionTest
|
||||||
condition = new Condition(Operator.LT, Long.toString(randomLong()));
|
condition = new Condition(Operator.LT, Long.toString(randomLong()));
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
fieldName = randomAlphaOfLengthBetween(1, 20);
|
fieldName = randomAlphaOfLengthBetween(1, 20);
|
||||||
fieldValue = randomAlphaOfLengthBetween(1, 20);
|
fieldValue = randomAlphaOfLengthBetween(1, 20);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return new RuleCondition(r, fieldName, fieldValue, condition, valueFilter);
|
return new RuleCondition(type, fieldName, fieldValue, condition, valueFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -201,6 +198,7 @@ public class RuleConditionTests extends AbstractSerializingTestCase<RuleConditio
|
||||||
public void testVerify_GivenValidCategorical() {
|
public void testVerify_GivenValidCategorical() {
|
||||||
// no validation error:
|
// no validation error:
|
||||||
new RuleCondition(RuleConditionType.CATEGORICAL, "metric", null, null, "myFilter");
|
new RuleCondition(RuleConditionType.CATEGORICAL, "metric", null, null, "myFilter");
|
||||||
|
new RuleCondition(RuleConditionType.CATEGORICAL_COMPLEMENT, "metric", null, null, "myFilter");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testVerify_GivenValidNumericalActual() {
|
public void testVerify_GivenValidNumericalActual() {
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class RuleConditionTypeTests extends ESTestCase {
|
||||||
|
|
||||||
public void testToString() {
|
public void testToString() {
|
||||||
assertEquals("categorical", RuleConditionType.CATEGORICAL.toString());
|
assertEquals("categorical", RuleConditionType.CATEGORICAL.toString());
|
||||||
|
assertEquals("categorical_complement", RuleConditionType.CATEGORICAL_COMPLEMENT.toString());
|
||||||
assertEquals("numerical_actual", RuleConditionType.NUMERICAL_ACTUAL.toString());
|
assertEquals("numerical_actual", RuleConditionType.NUMERICAL_ACTUAL.toString());
|
||||||
assertEquals("numerical_typical", RuleConditionType.NUMERICAL_TYPICAL.toString());
|
assertEquals("numerical_typical", RuleConditionType.NUMERICAL_TYPICAL.toString());
|
||||||
assertEquals("numerical_diff_abs", RuleConditionType.NUMERICAL_DIFF_ABS.toString());
|
assertEquals("numerical_diff_abs", RuleConditionType.NUMERICAL_DIFF_ABS.toString());
|
||||||
|
@ -122,7 +123,18 @@ public class RuleConditionTypeTests extends ESTestCase {
|
||||||
} else {
|
} else {
|
||||||
assertFalse(isNumerical);
|
assertFalse(isNumerical);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIsCategorical() {
|
||||||
|
for (RuleConditionType type : EnumSet.allOf(RuleConditionType.class)) {
|
||||||
|
boolean isCategorical = type.isCategorical();
|
||||||
|
if (type == RuleConditionType.CATEGORICAL ||
|
||||||
|
type == RuleConditionType.CATEGORICAL_COMPLEMENT) {
|
||||||
|
assertTrue(isCategorical);
|
||||||
|
} else {
|
||||||
|
assertFalse(isCategorical);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue