Introduce Annotation.event field (#57144) (#57453)

This commit is contained in:
Przemysław Witek 2020-06-01 20:42:25 +02:00 committed by GitHub
parent 4d54bb3917
commit ceb4b29b98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 124 additions and 36 deletions

View File

@ -14,15 +14,46 @@ import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.common.time.TimeUtils;
import org.elasticsearch.xpack.core.ml.job.config.Job;
import java.io.IOException;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
public class Annotation implements ToXContentObject, Writeable {
public enum Type {
ANNOTATION,
COMMENT;
public static Type fromString(String value) {
return valueOf(value.toUpperCase(Locale.ROOT));
}
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
public enum Event {
USER,
DELAYED_DATA,
MODEL_SNAPSHOT_STORED;
public static Event fromString(String value) {
return valueOf(value.toUpperCase(Locale.ROOT));
}
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
public static final ParseField ANNOTATION = new ParseField("annotation");
public static final ParseField CREATE_TIME = new ParseField("create_time");
public static final ParseField CREATE_USERNAME = new ParseField("create_username");
@ -31,6 +62,7 @@ public class Annotation implements ToXContentObject, Writeable {
public static final ParseField MODIFIED_TIME = new ParseField("modified_time");
public static final ParseField MODIFIED_USERNAME = new ParseField("modified_username");
public static final ParseField TYPE = new ParseField("type");
public static final ParseField EVENT = new ParseField("event");
public static final ParseField DETECTOR_INDEX = new ParseField("detector_index");
public static final ParseField PARTITION_FIELD_NAME = new ParseField("partition_field_name");
public static final ParseField PARTITION_FIELD_VALUE = new ParseField("partition_field_value");
@ -39,29 +71,50 @@ public class Annotation implements ToXContentObject, Writeable {
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 ObjectParser<Builder, Void> PARSER = new ObjectParser<>(TYPE.getPreferredName(), true, Builder::new);
/**
* Parses {@link Annotation} using a strict parser.
*/
public static Annotation fromXContent(XContentParser parser, Void context) {
return STRICT_PARSER.apply(parser, context).build();
}
/**
* Strict parser for cases when {@link Annotation} is returned from C++ as an ML result.
*/
private static final ObjectParser<Builder, Void> STRICT_PARSER = new ObjectParser<>(ANNOTATION.getPreferredName(), false, Builder::new);
static {
PARSER.declareString(Builder::setAnnotation, ANNOTATION);
PARSER.declareField(Builder::setCreateTime,
STRICT_PARSER.declareString(Builder::setAnnotation, ANNOTATION);
STRICT_PARSER.declareField(Builder::setCreateTime,
p -> TimeUtils.parseTimeField(p, CREATE_TIME.getPreferredName()), CREATE_TIME, ObjectParser.ValueType.VALUE);
PARSER.declareString(Builder::setCreateUsername, CREATE_USERNAME);
PARSER.declareField(Builder::setTimestamp,
STRICT_PARSER.declareString(Builder::setCreateUsername, CREATE_USERNAME);
STRICT_PARSER.declareField(Builder::setTimestamp,
p -> TimeUtils.parseTimeField(p, TIMESTAMP.getPreferredName()), TIMESTAMP, ObjectParser.ValueType.VALUE);
PARSER.declareField(Builder::setEndTimestamp,
STRICT_PARSER.declareField(Builder::setEndTimestamp,
p -> TimeUtils.parseTimeField(p, END_TIMESTAMP.getPreferredName()), END_TIMESTAMP, ObjectParser.ValueType.VALUE);
PARSER.declareString(Builder::setJobId, Job.ID);
PARSER.declareField(Builder::setModifiedTime,
STRICT_PARSER.declareString(Builder::setJobId, Job.ID);
STRICT_PARSER.declareField(Builder::setModifiedTime,
p -> TimeUtils.parseTimeField(p, MODIFIED_TIME.getPreferredName()), MODIFIED_TIME, ObjectParser.ValueType.VALUE);
PARSER.declareString(Builder::setModifiedUsername, MODIFIED_USERNAME);
PARSER.declareString(Builder::setType, TYPE);
PARSER.declareInt(Builder::setDetectorIndex, DETECTOR_INDEX);
PARSER.declareString(Builder::setPartitionFieldName, PARTITION_FIELD_NAME);
PARSER.declareString(Builder::setPartitionFieldValue, PARTITION_FIELD_VALUE);
PARSER.declareString(Builder::setOverFieldName, OVER_FIELD_NAME);
PARSER.declareString(Builder::setOverFieldValue, OVER_FIELD_VALUE);
PARSER.declareString(Builder::setByFieldName, BY_FIELD_NAME);
PARSER.declareString(Builder::setByFieldValue, BY_FIELD_VALUE);
STRICT_PARSER.declareString(Builder::setModifiedUsername, MODIFIED_USERNAME);
STRICT_PARSER.declareField(Builder::setType, p -> {
if (p.currentToken() == XContentParser.Token.VALUE_STRING) {
return Type.fromString(p.text());
}
throw new IllegalArgumentException("Unsupported token [" + p.currentToken() + "]");
}, TYPE, ObjectParser.ValueType.STRING);
STRICT_PARSER.declareField(Builder::setEvent, p -> {
if (p.currentToken() == XContentParser.Token.VALUE_STRING) {
return Event.fromString(p.text());
}
throw new IllegalArgumentException("Unsupported token [" + p.currentToken() + "]");
}, EVENT, ObjectParser.ValueType.STRING);
STRICT_PARSER.declareInt(Builder::setDetectorIndex, DETECTOR_INDEX);
STRICT_PARSER.declareString(Builder::setPartitionFieldName, PARTITION_FIELD_NAME);
STRICT_PARSER.declareString(Builder::setPartitionFieldValue, PARTITION_FIELD_VALUE);
STRICT_PARSER.declareString(Builder::setOverFieldName, OVER_FIELD_NAME);
STRICT_PARSER.declareString(Builder::setOverFieldValue, OVER_FIELD_VALUE);
STRICT_PARSER.declareString(Builder::setByFieldName, BY_FIELD_NAME);
STRICT_PARSER.declareString(Builder::setByFieldValue, BY_FIELD_VALUE);
}
private final String annotation;
@ -75,7 +128,8 @@ public class Annotation implements ToXContentObject, Writeable {
private final String jobId;
private final Date modifiedTime;
private final String modifiedUsername;
private final String type;
private final Type type;
private final Event event;
/**
* Scope-related fields.
*/
@ -88,8 +142,9 @@ public class Annotation implements ToXContentObject, Writeable {
private final String byFieldValue;
private Annotation(String annotation, Date createTime, String createUsername, Date timestamp, Date endTimestamp, String jobId,
Date modifiedTime, String modifiedUsername, String type, Integer detectorIndex, String partitionFieldName,
String partitionFieldValue, String overFieldName, String overFieldValue, String byFieldName, String byFieldValue) {
Date modifiedTime, String modifiedUsername, Type type, Event event, Integer detectorIndex,
String partitionFieldName, String partitionFieldValue, String overFieldName, String overFieldValue,
String byFieldName, String byFieldValue) {
this.annotation = Objects.requireNonNull(annotation);
this.createTime = Objects.requireNonNull(createTime);
this.createUsername = Objects.requireNonNull(createUsername);
@ -99,6 +154,7 @@ public class Annotation implements ToXContentObject, Writeable {
this.modifiedTime = modifiedTime;
this.modifiedUsername = modifiedUsername;
this.type = Objects.requireNonNull(type);
this.event = event;
this.detectorIndex = detectorIndex;
this.partitionFieldName = partitionFieldName;
this.partitionFieldValue = partitionFieldValue;
@ -125,8 +181,9 @@ public class Annotation implements ToXContentObject, Writeable {
modifiedTime = null;
}
modifiedUsername = in.readOptionalString();
type = in.readString();
type = Type.fromString(in.readString());
if (in.getVersion().onOrAfter(Version.V_7_9_0)) {
event = in.readBoolean() ? in.readEnum(Event.class) : null;
detectorIndex = in.readOptionalInt();
partitionFieldName = in.readOptionalString();
partitionFieldValue = in.readOptionalString();
@ -135,6 +192,7 @@ public class Annotation implements ToXContentObject, Writeable {
byFieldName = in.readOptionalString();
byFieldValue = in.readOptionalString();
} else {
event = null;
detectorIndex = null;
partitionFieldName = null;
partitionFieldValue = null;
@ -165,8 +223,14 @@ public class Annotation implements ToXContentObject, Writeable {
out.writeBoolean(false);
}
out.writeOptionalString(modifiedUsername);
out.writeString(type);
out.writeString(type.toString());
if (out.getVersion().onOrAfter(Version.V_7_9_0)) {
if (event != null) {
out.writeBoolean(true);
out.writeEnum(event);
} else {
out.writeBoolean(false);
}
out.writeOptionalInt(detectorIndex);
out.writeOptionalString(partitionFieldName);
out.writeOptionalString(partitionFieldValue);
@ -209,10 +273,14 @@ public class Annotation implements ToXContentObject, Writeable {
return modifiedUsername;
}
public String getType() {
public Type getType() {
return type;
}
public Event getEvent() {
return event;
}
public Integer getDetectorIndex() {
return detectorIndex;
}
@ -261,6 +329,9 @@ public class Annotation implements ToXContentObject, Writeable {
builder.field(MODIFIED_USERNAME.getPreferredName(), modifiedUsername);
}
builder.field(TYPE.getPreferredName(), type);
if (event != null) {
builder.field(EVENT.getPreferredName(), event);
}
if (detectorIndex != null) {
builder.field(DETECTOR_INDEX.getPreferredName(), detectorIndex);
}
@ -289,7 +360,7 @@ public class Annotation implements ToXContentObject, Writeable {
@Override
public int hashCode() {
return Objects.hash(
annotation, createTime, createUsername, timestamp, endTimestamp, jobId, modifiedTime, modifiedUsername, type,
annotation, createTime, createUsername, timestamp, endTimestamp, jobId, modifiedTime, modifiedUsername, type, event,
detectorIndex, partitionFieldName, partitionFieldValue, overFieldName, overFieldValue, byFieldName, byFieldValue);
}
@ -311,6 +382,7 @@ public class Annotation implements ToXContentObject, Writeable {
Objects.equals(modifiedTime, other.modifiedTime) &&
Objects.equals(modifiedUsername, other.modifiedUsername) &&
Objects.equals(type, other.type) &&
Objects.equals(event, other.event) &&
Objects.equals(detectorIndex, other.detectorIndex) &&
Objects.equals(partitionFieldName, other.partitionFieldName) &&
Objects.equals(partitionFieldValue, other.partitionFieldValue) &&
@ -338,7 +410,8 @@ public class Annotation implements ToXContentObject, Writeable {
private String jobId;
private Date modifiedTime;
private String modifiedUsername;
private String type;
private Type type;
private Event event;
private Integer detectorIndex;
private String partitionFieldName;
private String partitionFieldValue;
@ -360,6 +433,7 @@ public class Annotation implements ToXContentObject, Writeable {
this.modifiedTime = other.modifiedTime == null ? null : new Date(other.modifiedTime.getTime());
this.modifiedUsername = other.modifiedUsername;
this.type = other.type;
this.event = other.event;
this.detectorIndex = other.detectorIndex;
this.partitionFieldName = other.partitionFieldName;
this.partitionFieldValue = other.partitionFieldValue;
@ -409,11 +483,16 @@ public class Annotation implements ToXContentObject, Writeable {
return this;
}
public Builder setType(String type) {
public Builder setType(Type type) {
this.type = Objects.requireNonNull(type);
return this;
}
public Builder setEvent(Event event) {
this.event = event;
return this;
}
public Builder setDetectorIndex(Integer index) {
this.detectorIndex = index;
return this;
@ -451,7 +530,7 @@ public class Annotation implements ToXContentObject, Writeable {
public Annotation build() {
return new Annotation(
annotation, createTime, createUsername, timestamp, endTimestamp, jobId, modifiedTime, modifiedUsername, type,
annotation, createTime, createUsername, timestamp, endTimestamp, jobId, modifiedTime, modifiedUsername, type, event,
detectorIndex, partitionFieldName, partitionFieldValue, overFieldName, overFieldValue, byFieldName, byFieldValue);
}
}

View File

@ -31,6 +31,9 @@
"type" : {
"type" : "keyword"
},
"event" : {
"type" : "keyword"
},
"detector_index" : {
"type" : "integer"
},

View File

@ -17,7 +17,7 @@ public class AnnotationTests extends AbstractSerializingTestCase<Annotation> {
@Override
protected Annotation doParseInstance(XContentParser parser) {
return Annotation.PARSER.apply(parser, null).build();
return Annotation.fromXContent(parser, null);
}
@Override
@ -35,7 +35,8 @@ public class AnnotationTests extends AbstractSerializingTestCase<Annotation> {
.setJobId(jobId)
.setModifiedTime(randomBoolean() ? new Date(randomNonNegativeLong()) : null)
.setModifiedUsername(randomBoolean() ? randomAlphaOfLengthBetween(5, 20) : null)
.setType(randomAlphaOfLengthBetween(10, 15))
.setType(randomFrom(Annotation.Type.values()))
.setEvent(randomBoolean() ? randomFrom(Annotation.Event.values()) : null)
.setDetectorIndex(randomBoolean() ? randomIntBetween(0, 10) : null)
.setPartitionFieldName(randomBoolean() ? randomAlphaOfLengthBetween(5, 20) : null)
.setPartitionFieldValue(randomBoolean() ? randomAlphaOfLengthBetween(5, 20) : null)

View File

@ -684,7 +684,7 @@ public class AutodetectResultProcessorIT extends MlSingleNodeTestCase {
private Annotation parseAnnotation(BytesReference source) throws IOException {
try (XContentParser parser = createParser(jsonXContent, source)) {
return Annotation.PARSER.parse(parser, null).build();
return Annotation.fromXContent(parser, null);
}
}

View File

@ -244,7 +244,8 @@ class DatafeedJob {
.setJobId(jobId)
.setModifiedTime(currentTime)
.setModifiedUsername(XPackUser.NAME)
.setType("annotation")
.setType(Annotation.Type.ANNOTATION)
.setEvent(Annotation.Event.DELAYED_DATA)
.build();
}

View File

@ -369,7 +369,8 @@ public class AutodetectResultProcessor {
.setJobId(jobId)
.setModifiedTime(currentTime)
.setModifiedUsername(XPackUser.NAME)
.setType("annotation")
.setType(Annotation.Type.ANNOTATION)
.setEvent(Annotation.Event.MODEL_SNAPSHOT_STORED)
.build();
}

View File

@ -234,7 +234,7 @@ public class AnnotationPersisterTests extends ESTestCase {
private Annotation parseAnnotation(BytesReference source) throws IOException {
try (XContentParser parser = createParser(jsonXContent, source)) {
return Annotation.PARSER.parse(parser, null).build();
return Annotation.fromXContent(parser, null);
}
}
}

View File

@ -297,7 +297,8 @@ public class DatafeedJobTests extends ESTestCase {
.setJobId(jobId)
.setModifiedTime(new Date(annotationCreateTime))
.setModifiedUsername(XPackUser.NAME)
.setType("annotation")
.setType(Annotation.Type.ANNOTATION)
.setEvent(Annotation.Event.DELAYED_DATA)
.build();
BytesReference expectedSource =
BytesReference.bytes(expectedAnnotation.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS));
@ -343,7 +344,8 @@ public class DatafeedJobTests extends ESTestCase {
.setJobId(jobId)
.setModifiedTime(new Date(annotationUpdateTime))
.setModifiedUsername(XPackUser.NAME)
.setType("annotation")
.setType(Annotation.Type.ANNOTATION)
.setEvent(Annotation.Event.DELAYED_DATA)
.build();
BytesReference expectedSource =
BytesReference.bytes(expectedUpdatedAnnotation.toXContent(XContentFactory.jsonBuilder(), ToXContent.EMPTY_PARAMS));

View File

@ -396,7 +396,8 @@ public class AutodetectResultProcessorTests extends ESTestCase {
.setJobId(JOB_ID)
.setModifiedTime(Date.from(CURRENT_TIME))
.setModifiedUsername(XPackUser.NAME)
.setType("annotation")
.setType(Annotation.Type.ANNOTATION)
.setEvent(Annotation.Event.MODEL_SNAPSHOT_STORED)
.build();
assertThat(annotation, is(equalTo(expectedAnnotation)));