[ML] Change forecast_id to UUid, add create_time and start_time (elastic/x-pack-elasticsearch#3095)

relates elastic/x-pack-elasticsearch#3093

Original commit: elastic/x-pack-elasticsearch@f586189851
This commit is contained in:
Dimitris Athanasiou 2017-11-23 14:46:52 +00:00 committed by GitHub
parent a8b5b138a7
commit e0affd455d
16 changed files with 358 additions and 120 deletions

View File

@ -175,13 +175,13 @@ public class ForecastJobAction extends Action<ForecastJobAction.Request, Forecas
public static class Response extends BaseTasksResponse implements Writeable, ToXContentObject { public static class Response extends BaseTasksResponse implements Writeable, ToXContentObject {
private boolean acknowledged; private boolean acknowledged;
private long forecastId; private String forecastId;
Response() { Response() {
super(null, null); super(null, null);
} }
Response(boolean acknowledged, long forecastId) { Response(boolean acknowledged, String forecastId) {
super(null, null); super(null, null);
this.acknowledged = acknowledged; this.acknowledged = acknowledged;
this.forecastId = forecastId; this.forecastId = forecastId;
@ -191,7 +191,7 @@ public class ForecastJobAction extends Action<ForecastJobAction.Request, Forecas
return acknowledged; return acknowledged;
} }
public long getForecastId() { public String getForecastId() {
return forecastId; return forecastId;
} }
@ -199,14 +199,14 @@ public class ForecastJobAction extends Action<ForecastJobAction.Request, Forecas
public void readFrom(StreamInput in) throws IOException { public void readFrom(StreamInput in) throws IOException {
super.readFrom(in); super.readFrom(in);
acknowledged = in.readBoolean(); acknowledged = in.readBoolean();
forecastId = in.readLong(); forecastId = in.readString();
} }
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out); super.writeTo(out);
out.writeBoolean(acknowledged); out.writeBoolean(acknowledged);
out.writeLong(forecastId); out.writeString(forecastId);
} }
@Override @Override
@ -227,7 +227,7 @@ public class ForecastJobAction extends Action<ForecastJobAction.Request, Forecas
return false; return false;
} }
Response other = (Response) obj; Response other = (Response) obj;
return this.acknowledged == other.acknowledged && this.forecastId == other.forecastId; return this.acknowledged == other.acknowledged && Objects.equals(this.forecastId, other.forecastId);
} }
@Override @Override

View File

@ -336,12 +336,18 @@ public class ElasticsearchMappings {
.field(TYPE, DOUBLE) .field(TYPE, DOUBLE)
.endObject() .endObject()
.startObject(Forecast.FORECAST_ID.getPreferredName()) .startObject(Forecast.FORECAST_ID.getPreferredName())
.field(TYPE, LONG) .field(TYPE, KEYWORD)
.endObject(); .endObject();
// Forecast Stats Output // Forecast Stats Output
// re-used: TIMESTAMP, PROCESSING_TIME_MS, PROCESSED_RECORD_COUNT, LATEST_RECORD_TIME // re-used: TIMESTAMP, PROCESSING_TIME_MS, PROCESSED_RECORD_COUNT, LATEST_RECORD_TIME
builder.startObject(ForecastRequestStats.END_TIME.getPreferredName()) builder.startObject(ForecastRequestStats.START_TIME.getPreferredName())
.field(TYPE, DATE)
.endObject()
.startObject(ForecastRequestStats.END_TIME.getPreferredName())
.field(TYPE, DATE)
.endObject()
.startObject(ForecastRequestStats.CREATE_TIME.getPreferredName())
.field(TYPE, DATE) .field(TYPE, DATE)
.endObject() .endObject()
.startObject(ForecastRequestStats.EXPIRY_TIME.getPreferredName()) .startObject(ForecastRequestStats.EXPIRY_TIME.getPreferredName())
@ -355,6 +361,9 @@ public class ElasticsearchMappings {
.endObject() .endObject()
.startObject(ForecastRequestStats.STATUS.getPreferredName()) .startObject(ForecastRequestStats.STATUS.getPreferredName())
.field(TYPE, KEYWORD) .field(TYPE, KEYWORD)
.endObject()
.startObject(ForecastRequestStats.MEMORY_USAGE.getPreferredName())
.field(TYPE, LONG)
.endObject(); .endObject();
} }

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ml.job.process.autodetect.params;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.index.mapper.DateFieldMapper;
@ -16,18 +17,32 @@ import java.util.Objects;
public class ForecastParams { public class ForecastParams {
private final String forecastId;
private final long createTime;
private final long endTime; private final long endTime;
private final long duration; private final long duration;
private final long expiresIn; private final long expiresIn;
private final long forecastId;
private ForecastParams(long forecastId, long endTime, long duration, long expiresIn) { private ForecastParams(String forecastId, long createTime, long endTime, long duration, long expiresIn) {
this.forecastId = forecastId; this.forecastId = forecastId;
this.createTime = createTime;
this.endTime = endTime; this.endTime = endTime;
this.duration = duration; this.duration = duration;
this.expiresIn = expiresIn; this.expiresIn = expiresIn;
} }
public String getForecastId() {
return forecastId;
}
/**
* The forecast create time in seconds from the epoch
* @return The create time in seconds from the epoch
*/
public long getCreateTime() {
return createTime;
}
/** /**
* The forecast end time in seconds from the epoch * The forecast end time in seconds from the epoch
* @return The end time in seconds from the epoch * @return The end time in seconds from the epoch
@ -52,18 +67,9 @@ public class ForecastParams {
return expiresIn; return expiresIn;
} }
/**
* The forecast id
*
* @return The forecast Id
*/
public long getForecastId() {
return forecastId;
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(forecastId, endTime, duration, expiresIn); return Objects.hash(forecastId, createTime, endTime, duration, expiresIn);
} }
@Override @Override
@ -75,8 +81,11 @@ public class ForecastParams {
return false; return false;
} }
ForecastParams other = (ForecastParams) obj; ForecastParams other = (ForecastParams) obj;
return Objects.equals(forecastId, other.forecastId) && Objects.equals(endTime, other.endTime) && return Objects.equals(forecastId, other.forecastId)
Objects.equals(duration, other.duration) && Objects.equals(expiresIn, other.expiresIn); && Objects.equals(createTime, other.createTime)
&& Objects.equals(endTime, other.endTime)
&& Objects.equals(duration, other.duration)
&& Objects.equals(expiresIn, other.expiresIn);
} }
public static Builder builder() { public static Builder builder() {
@ -84,26 +93,22 @@ public class ForecastParams {
} }
public static class Builder { public static class Builder {
private final String forecastId;
private final long createTimeEpochSecs;
private long endTimeEpochSecs; private long endTimeEpochSecs;
private long durationSecs; private long durationSecs;
private long expiresInSecs; private long expiresInSecs;
private long startTime;
private long forecastId;
private Builder() { private Builder() {
startTime = System.currentTimeMillis(); forecastId = UUIDs.base64UUID();
createTimeEpochSecs = System.currentTimeMillis() / 1000;
endTimeEpochSecs = 0; endTimeEpochSecs = 0;
forecastId = generateId();
durationSecs = 0; durationSecs = 0;
// because 0 means never expire, the default is -1 // because 0 means never expire, the default is -1
expiresInSecs = -1; expiresInSecs = -1;
} }
private long generateId() {
return startTime;
}
public Builder endTime(String endTime, ParseField paramName) { public Builder endTime(String endTime, ParseField paramName) {
DateMathParser dateMathParser = new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); DateMathParser dateMathParser = new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER);
@ -132,7 +137,7 @@ public class ForecastParams {
throw new ElasticsearchParseException(Messages.getMessage(Messages.REST_INVALID_DURATION_AND_ENDTIME)); throw new ElasticsearchParseException(Messages.getMessage(Messages.REST_INVALID_DURATION_AND_ENDTIME));
} }
return new ForecastParams(forecastId, endTimeEpochSecs, durationSecs, expiresInSecs); return new ForecastParams(forecastId, createTimeEpochSecs, endTimeEpochSecs, durationSecs, expiresInSecs);
} }
} }
} }

View File

@ -151,9 +151,9 @@ public class ControlMsgToProcessWriter {
} }
public void writeForecastMessage(ForecastParams params) throws IOException { public void writeForecastMessage(ForecastParams params) throws IOException {
XContentBuilder builder = XContentFactory.jsonBuilder() XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
.startObject() builder.field("forecast_id", params.getForecastId());
.field("forecast_id", params.getForecastId()); builder.field("create_time", params.getCreateTime());
if (params.getEndTime() != 0) { if (params.getEndTime() != 0) {
builder.field("end_time", params.getEndTime()); builder.field("end_time", params.getEndTime());

View File

@ -45,11 +45,11 @@ public class Forecast implements ToXContentObject, Writeable {
public static final ConstructingObjectParser<Forecast, Void> PARSER = public static final ConstructingObjectParser<Forecast, Void> PARSER =
new ConstructingObjectParser<>(RESULT_TYPE_VALUE, a -> new ConstructingObjectParser<>(RESULT_TYPE_VALUE, a ->
new Forecast((String) a[0], (long) a[1], (Date) a[2], (long) a[3], (int) a[4])); new Forecast((String) a[0], (String) a[1], (Date) a[2], (long) a[3], (int) a[4]));
static { static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID); PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FORECAST_ID); PARSER.declareString(ConstructingObjectParser.constructorArg(), FORECAST_ID);
PARSER.declareField(ConstructingObjectParser.constructorArg(), p -> { PARSER.declareField(ConstructingObjectParser.constructorArg(), p -> {
if (p.currentToken() == Token.VALUE_NUMBER) { if (p.currentToken() == Token.VALUE_NUMBER) {
return new Date(p.longValue()); return new Date(p.longValue());
@ -73,7 +73,7 @@ public class Forecast implements ToXContentObject, Writeable {
} }
private final String jobId; private final String jobId;
private final long forecastId; private final String forecastId;
private final Date timestamp; private final Date timestamp;
private final long bucketSpan; private final long bucketSpan;
private int detectorIndex; private int detectorIndex;
@ -86,9 +86,9 @@ public class Forecast implements ToXContentObject, Writeable {
private double forecastUpper; private double forecastUpper;
private double forecastPrediction; private double forecastPrediction;
public Forecast(String jobId, long forecastId, Date timestamp, long bucketSpan, int detectorIndex) { public Forecast(String jobId, String forecastId, Date timestamp, long bucketSpan, int detectorIndex) {
this.jobId = jobId; this.jobId = Objects.requireNonNull(jobId);
this.forecastId = forecastId; this.forecastId = Objects.requireNonNull(forecastId);
this.timestamp = timestamp; this.timestamp = timestamp;
this.bucketSpan = bucketSpan; this.bucketSpan = bucketSpan;
this.detectorIndex = detectorIndex; this.detectorIndex = detectorIndex;
@ -96,7 +96,7 @@ public class Forecast implements ToXContentObject, Writeable {
public Forecast(StreamInput in) throws IOException { public Forecast(StreamInput in) throws IOException {
jobId = in.readString(); jobId = in.readString();
forecastId = in.readLong(); forecastId = in.readString();
timestamp = new Date(in.readLong()); timestamp = new Date(in.readLong());
partitionFieldName = in.readOptionalString(); partitionFieldName = in.readOptionalString();
partitionFieldValue = in.readOptionalString(); partitionFieldValue = in.readOptionalString();
@ -113,7 +113,7 @@ public class Forecast implements ToXContentObject, Writeable {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeString(jobId); out.writeString(jobId);
out.writeLong(forecastId); out.writeString(forecastId);
out.writeLong(timestamp.getTime()); out.writeLong(timestamp.getTime());
out.writeOptionalString(partitionFieldName); out.writeOptionalString(partitionFieldName);
out.writeOptionalString(partitionFieldValue); out.writeOptionalString(partitionFieldValue);
@ -165,7 +165,7 @@ public class Forecast implements ToXContentObject, Writeable {
return jobId; return jobId;
} }
public long getForecastId() { public String getForecastId() {
return forecastId; return forecastId;
} }
@ -264,7 +264,7 @@ public class Forecast implements ToXContentObject, Writeable {
} }
Forecast that = (Forecast) other; Forecast that = (Forecast) other;
return Objects.equals(this.jobId, that.jobId) && return Objects.equals(this.jobId, that.jobId) &&
forecastId == that.forecastId && Objects.equals(this.forecastId, that.forecastId) &&
Objects.equals(this.timestamp, that.timestamp) && Objects.equals(this.timestamp, that.timestamp) &&
Objects.equals(this.partitionFieldValue, that.partitionFieldValue) && Objects.equals(this.partitionFieldValue, that.partitionFieldValue) &&
Objects.equals(this.partitionFieldName, that.partitionFieldName) && Objects.equals(this.partitionFieldName, that.partitionFieldName) &&

View File

@ -10,9 +10,9 @@ 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;
import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
import org.elasticsearch.xpack.ml.job.config.Job; import org.elasticsearch.xpack.ml.job.config.Job;
import java.io.IOException; import java.io.IOException;
@ -36,7 +36,9 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
public static final ParseField RESULTS_FIELD = new ParseField(RESULT_TYPE_VALUE); public static final ParseField RESULTS_FIELD = new ParseField(RESULT_TYPE_VALUE);
public static final ParseField FORECAST_ID = new ParseField("forecast_id"); public static final ParseField FORECAST_ID = new ParseField("forecast_id");
public static final ParseField START_TIME = new ParseField("forecast_start_timestamp");
public static final ParseField END_TIME = new ParseField("forecast_end_timestamp"); public static final ParseField END_TIME = new ParseField("forecast_end_timestamp");
public static final ParseField CREATE_TIME = new ParseField("forecast_create_timestamp");
public static final ParseField EXPIRY_TIME = new ParseField("forecast_expiry_timestamp"); public static final ParseField EXPIRY_TIME = new ParseField("forecast_expiry_timestamp");
public static final ParseField MESSAGES = new ParseField("forecast_messages"); public static final ParseField MESSAGES = new ParseField("forecast_messages");
public static final ParseField PROCESSING_TIME_MS = new ParseField("processing_time_ms"); public static final ParseField PROCESSING_TIME_MS = new ParseField("processing_time_ms");
@ -46,20 +48,24 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
public static final ParseField MEMORY_USAGE = new ParseField("forecast_memory_bytes"); public static final ParseField MEMORY_USAGE = new ParseField("forecast_memory_bytes");
public static final ConstructingObjectParser<ForecastRequestStats, Void> PARSER = public static final ConstructingObjectParser<ForecastRequestStats, Void> PARSER =
new ConstructingObjectParser<>(RESULT_TYPE_VALUE, a -> new ForecastRequestStats((String) a[0], (long) a[1])); new ConstructingObjectParser<>(RESULT_TYPE_VALUE, a -> new ForecastRequestStats((String) a[0], (String) a[1]));
static { static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID); PARSER.declareString(ConstructingObjectParser.constructorArg(), Job.ID);
PARSER.declareLong(ConstructingObjectParser.constructorArg(), FORECAST_ID); PARSER.declareString(ConstructingObjectParser.constructorArg(), FORECAST_ID);
PARSER.declareString((modelForecastRequestStats, s) -> {}, Result.RESULT_TYPE); PARSER.declareString((modelForecastRequestStats, s) -> {}, Result.RESULT_TYPE);
PARSER.declareLong(ForecastRequestStats::setRecordCount, PROCESSED_RECORD_COUNT); PARSER.declareLong(ForecastRequestStats::setRecordCount, PROCESSED_RECORD_COUNT);
PARSER.declareStringArray(ForecastRequestStats::setMessages, MESSAGES); PARSER.declareStringArray(ForecastRequestStats::setMessages, MESSAGES);
PARSER.declareField(ForecastRequestStats::setTimeStamp, PARSER.declareField(ForecastRequestStats::setTimeStamp,
p -> Instant.ofEpochMilli(p.longValue()), Result.TIMESTAMP, ValueType.LONG); p -> Instant.ofEpochMilli(p.longValue()), Result.TIMESTAMP, ValueType.LONG);
PARSER.declareField(ForecastRequestStats::setEndTimeStamp, PARSER.declareField(ForecastRequestStats::setStartTime,
p -> Instant.ofEpochMilli(p.longValue()), START_TIME, ValueType.LONG);
PARSER.declareField(ForecastRequestStats::setEndTime,
p -> Instant.ofEpochMilli(p.longValue()), END_TIME, ValueType.LONG); p -> Instant.ofEpochMilli(p.longValue()), END_TIME, ValueType.LONG);
PARSER.declareField(ForecastRequestStats::setExpiryTimeStamp, PARSER.declareField(ForecastRequestStats::setCreateTime,
p -> Instant.ofEpochMilli(p.longValue()), CREATE_TIME, ValueType.LONG);
PARSER.declareField(ForecastRequestStats::setExpiryTime,
p -> Instant.ofEpochMilli(p.longValue()), EXPIRY_TIME, ValueType.LONG); p -> Instant.ofEpochMilli(p.longValue()), EXPIRY_TIME, ValueType.LONG);
PARSER.declareDouble(ForecastRequestStats::setProgress, PROGRESS); PARSER.declareDouble(ForecastRequestStats::setProgress, PROGRESS);
PARSER.declareLong(ForecastRequestStats::setProcessingTime, PROCESSING_TIME_MS); PARSER.declareLong(ForecastRequestStats::setProcessingTime, PROCESSING_TIME_MS);
@ -90,34 +96,39 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
} }
private final String jobId; private final String jobId;
private final long forecastId; private final String forecastId;
private long recordCount; private long recordCount;
private List<String> messages; private List<String> messages;
private Instant dateStarted = Instant.EPOCH; private Instant timestamp = Instant.EPOCH;
private Instant dateEnded = Instant.EPOCH; private Instant startTime = Instant.EPOCH;
private Instant dateExpires = Instant.EPOCH; private Instant endTime = Instant.EPOCH;
private Instant createTime = Instant.EPOCH;
private Instant expiryTime = Instant.EPOCH;
private double progress; private double progress;
private long processingTime; private long processingTime;
private long memoryUsage; private long memoryUsage;
private ForecastRequestStatus status = ForecastRequestStatus.OK; private ForecastRequestStatus status = ForecastRequestStatus.OK;
public ForecastRequestStats(String jobId, long forecastId) { public ForecastRequestStats(String jobId, String forecastId) {
this.jobId = jobId; this.jobId = Objects.requireNonNull(jobId);
this.forecastId = forecastId; this.forecastId = Objects.requireNonNull(forecastId);
} }
public ForecastRequestStats(StreamInput in) throws IOException { public ForecastRequestStats(StreamInput in) throws IOException {
jobId = in.readString(); jobId = in.readString();
forecastId = in.readLong(); forecastId = in.readString();
recordCount = in.readLong(); recordCount = in.readLong();
if (in.readBoolean()) { if (in.readBoolean()) {
messages = in.readList(StreamInput::readString); messages = in.readList(StreamInput::readString);
} else { } else {
messages = null; messages = null;
} }
dateStarted = Instant.ofEpochMilli(in.readVLong());
dateEnded = Instant.ofEpochMilli(in.readVLong()); timestamp = Instant.ofEpochMilli(in.readVLong());
dateExpires = Instant.ofEpochMilli(in.readVLong()); startTime = Instant.ofEpochMilli(in.readVLong());
endTime = Instant.ofEpochMilli(in.readVLong());
createTime = Instant.ofEpochMilli(in.readVLong());
expiryTime = Instant.ofEpochMilli(in.readVLong());
progress = in.readDouble(); progress = in.readDouble();
processingTime = in.readLong(); processingTime = in.readLong();
setMemoryUsage(in.readLong()); setMemoryUsage(in.readLong());
@ -127,7 +138,7 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeString(jobId); out.writeString(jobId);
out.writeLong(forecastId); out.writeString(forecastId);
out.writeLong(recordCount); out.writeLong(recordCount);
if (messages != null) { if (messages != null) {
out.writeBoolean(true); out.writeBoolean(true);
@ -135,9 +146,11 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
} else { } else {
out.writeBoolean(false); out.writeBoolean(false);
} }
out.writeVLong(dateStarted.toEpochMilli()); out.writeVLong(timestamp.toEpochMilli());
out.writeVLong(dateEnded.toEpochMilli()); out.writeVLong(startTime.toEpochMilli());
out.writeVLong(dateExpires.toEpochMilli()); out.writeVLong(endTime.toEpochMilli());
out.writeVLong(createTime.toEpochMilli());
out.writeVLong(expiryTime.toEpochMilli());
out.writeDouble(progress); out.writeDouble(progress);
out.writeLong(processingTime); out.writeLong(processingTime);
out.writeLong(getMemoryUsage()); out.writeLong(getMemoryUsage());
@ -154,14 +167,20 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
if (messages != null) { if (messages != null) {
builder.field(MESSAGES.getPreferredName(), messages); builder.field(MESSAGES.getPreferredName(), messages);
} }
if (dateStarted.equals(Instant.EPOCH) == false) { if (timestamp.equals(Instant.EPOCH) == false) {
builder.field(Result.TIMESTAMP.getPreferredName(), dateStarted.toEpochMilli()); builder.field(Result.TIMESTAMP.getPreferredName(), timestamp.toEpochMilli());
} }
if (dateEnded.equals(Instant.EPOCH) == false) { if (startTime.equals(Instant.EPOCH) == false) {
builder.field(END_TIME.getPreferredName(), dateEnded.toEpochMilli()); builder.field(START_TIME.getPreferredName(), startTime.toEpochMilli());
} }
if (dateExpires.equals(Instant.EPOCH) == false) { if (endTime.equals(Instant.EPOCH) == false) {
builder.field(EXPIRY_TIME.getPreferredName(), dateExpires.toEpochMilli()); builder.field(END_TIME.getPreferredName(), endTime.toEpochMilli());
}
if (createTime.equals(Instant.EPOCH) == false) {
builder.field(CREATE_TIME.getPreferredName(), createTime.toEpochMilli());
}
if (expiryTime.equals(Instant.EPOCH) == false) {
builder.field(EXPIRY_TIME.getPreferredName(), expiryTime.toEpochMilli());
} }
builder.field(PROGRESS.getPreferredName(), progress); builder.field(PROGRESS.getPreferredName(), progress);
builder.field(PROCESSING_TIME_MS.getPreferredName(), processingTime); builder.field(PROCESSING_TIME_MS.getPreferredName(), processingTime);
@ -175,7 +194,7 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
return jobId; return jobId;
} }
public long getForecastId() { public String getForecastId() {
return forecastId; return forecastId;
} }
@ -193,7 +212,7 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
this.recordCount = recordCount; this.recordCount = recordCount;
} }
public double getRecordCount() { public long getRecordCount() {
return recordCount; return recordCount;
} }
@ -205,28 +224,44 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
this.messages = messages; this.messages = messages;
} }
public Instant getDateStarted() { public void setTimeStamp(Instant timestamp) {
return dateStarted; this.timestamp = timestamp;
} }
public void setTimeStamp(Instant dateStarted) { public Instant getTimestamp() {
this.dateStarted = dateStarted; return timestamp;
} }
public Instant getDateEnded() { public void setStartTime(Instant startTime) {
return dateEnded; this.startTime = startTime;
} }
public void setEndTimeStamp(Instant dateEnded) { public Instant getStartTime() {
this.dateEnded = dateEnded; return startTime;
} }
public void setExpiryTimeStamp(Instant dateExpires) { public Instant getEndTime() {
this.dateExpires = dateExpires; return endTime;
} }
public Instant getDateExpired() { public void setEndTime(Instant endTime) {
return dateExpires; this.endTime = endTime;
}
public void setCreateTime(Instant createTime) {
this.createTime = createTime;
}
public Instant getCreateTime() {
return createTime;
}
public void setExpiryTime(Instant expiryTime) {
this.expiryTime = expiryTime;
}
public Instant getExpiryTime() {
return expiryTime;
} }
/** /**
@ -278,12 +313,14 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
} }
ForecastRequestStats that = (ForecastRequestStats) other; ForecastRequestStats that = (ForecastRequestStats) other;
return Objects.equals(this.jobId, that.jobId) && return Objects.equals(this.jobId, that.jobId) &&
this.forecastId == that.forecastId && Objects.equals(this.forecastId, that.forecastId) &&
this.recordCount == that.recordCount && this.recordCount == that.recordCount &&
Objects.equals(this.messages, that.messages) && Objects.equals(this.messages, that.messages) &&
Objects.equals(this.dateStarted, that.dateStarted) && Objects.equals(this.timestamp, that.timestamp) &&
Objects.equals(this.dateEnded, that.dateEnded) && Objects.equals(this.startTime, that.startTime) &&
Objects.equals(this.dateExpires, that.dateExpires) && Objects.equals(this.endTime, that.endTime) &&
Objects.equals(this.createTime, that.createTime) &&
Objects.equals(this.expiryTime, that.expiryTime) &&
this.progress == that.progress && this.progress == that.progress &&
this.processingTime == that.processingTime && this.processingTime == that.processingTime &&
this.memoryUsage == that.memoryUsage && this.memoryUsage == that.memoryUsage &&
@ -292,7 +329,7 @@ public class ForecastRequestStats implements ToXContentObject, Writeable {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(jobId, forecastId, recordCount, messages, dateStarted, dateEnded, dateExpires, return Objects.hash(jobId, forecastId, recordCount, messages, timestamp, startTime, endTime, createTime, expiryTime,
progress, processingTime, memoryUsage, status); progress, processingTime, memoryUsage, status);
} }
} }

View File

@ -131,12 +131,15 @@ public final class ReservedFieldNames {
Forecast.FORECAST_PREDICTION.getPreferredName(), Forecast.FORECAST_PREDICTION.getPreferredName(),
Forecast.FORECAST_ID.getPreferredName(), Forecast.FORECAST_ID.getPreferredName(),
//re-use: ForecastRequestStats.TIMESTAMP //re-use: TIMESTAMP
ForecastRequestStats.START_TIME.getPreferredName(),
ForecastRequestStats.END_TIME.getPreferredName(), ForecastRequestStats.END_TIME.getPreferredName(),
ForecastRequestStats.CREATE_TIME.getPreferredName(),
ForecastRequestStats.EXPIRY_TIME.getPreferredName(), ForecastRequestStats.EXPIRY_TIME.getPreferredName(),
ForecastRequestStats.MESSAGES.getPreferredName(), ForecastRequestStats.MESSAGES.getPreferredName(),
ForecastRequestStats.PROGRESS.getPreferredName(), ForecastRequestStats.PROGRESS.getPreferredName(),
ForecastRequestStats.STATUS.getPreferredName(), ForecastRequestStats.STATUS.getPreferredName(),
ForecastRequestStats.MEMORY_USAGE.getPreferredName(),
ModelSizeStats.MODEL_BYTES_FIELD.getPreferredName(), ModelSizeStats.MODEL_BYTES_FIELD.getPreferredName(),
ModelSizeStats.TOTAL_BY_FIELD_COUNT_FIELD.getPreferredName(), ModelSizeStats.TOTAL_BY_FIELD_COUNT_FIELD.getPreferredName(),

View File

@ -119,7 +119,7 @@ public class ExpiredForecastsRemover implements MlDataRemover {
XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser( XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(
NamedXContentRegistry.EMPTY, hit.getSourceRef()); NamedXContentRegistry.EMPTY, hit.getSourceRef());
ForecastRequestStats forecastRequestStats = ForecastRequestStats.PARSER.apply(parser, null); ForecastRequestStats forecastRequestStats = ForecastRequestStats.PARSER.apply(parser, null);
if (forecastRequestStats.getDateExpired().toEpochMilli() < cutoffEpochMs) { if (forecastRequestStats.getExpiryTime().toEpochMilli() < cutoffEpochMs) {
forecastsToDelete.add(forecastRequestStats); forecastsToDelete.add(forecastRequestStats);
} }
} }

View File

@ -12,7 +12,7 @@ public class ForecastJobActionResponseTests extends AbstractStreamableTestCase<R
@Override @Override
protected Response createTestInstance() { protected Response createTestInstance() {
return new Response(randomBoolean(), randomNonNegativeLong()); return new Response(randomBoolean(), randomAlphaOfLength(20));
} }
@Override @Override

View File

@ -90,7 +90,7 @@ public class DeleteExpiredDataIT extends MlNativeAutodetectIntegTestCase {
registerJob(newJobBuilder("snapshots-retention-with-retain").setResultsRetentionDays(null).setModelSnapshotRetentionDays(2L)); registerJob(newJobBuilder("snapshots-retention-with-retain").setResultsRetentionDays(null).setModelSnapshotRetentionDays(2L));
registerJob(newJobBuilder("results-and-snapshots-retention").setResultsRetentionDays(1L).setModelSnapshotRetentionDays(2L)); registerJob(newJobBuilder("results-and-snapshots-retention").setResultsRetentionDays(1L).setModelSnapshotRetentionDays(2L));
List<Long> shortExpiryForecastIds = new ArrayList<>(); List<String> shortExpiryForecastIds = new ArrayList<>();
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long oneDayAgo = now - TimeValue.timeValueHours(48).getMillis() - 1; long oneDayAgo = now - TimeValue.timeValueHours(48).getMillis() - 1;
@ -123,16 +123,13 @@ public class DeleteExpiredDataIT extends MlNativeAutodetectIntegTestCase {
// Now let's create some forecasts // Now let's create some forecasts
openJob(job.getId()); openJob(job.getId());
long forecastShortExpiryId = forecast(job.getId(), TimeValue.timeValueHours(3), TimeValue.timeValueSeconds(1));
// We need to wait so that forecasts get different IDs // We must set a very small value for expires_in to keep this testable as the deletion cutoff point is the moment
awaitBusy(() -> false, 5, TimeUnit.MILLISECONDS); // the DeleteExpiredDataAction is called.
String forecastShortExpiryId = forecast(job.getId(), TimeValue.timeValueHours(3), TimeValue.timeValueSeconds(1));
shortExpiryForecastIds.add(forecastShortExpiryId); shortExpiryForecastIds.add(forecastShortExpiryId);
String forecastDefaultExpiryId = forecast(job.getId(), TimeValue.timeValueHours(3), null);
long forecastDefaultExpiryId = forecast(job.getId(), TimeValue.timeValueHours(3), null); String forecastNoExpiryId = forecast(job.getId(), TimeValue.timeValueHours(3), TimeValue.ZERO);
awaitBusy(() -> false, 5, TimeUnit.MILLISECONDS);
long forecastNoExpiryId = forecast(job.getId(), TimeValue.timeValueHours(3), TimeValue.ZERO);
waitForecastToFinish(job.getId(), forecastShortExpiryId); waitForecastToFinish(job.getId(), forecastShortExpiryId);
waitForecastToFinish(job.getId(), forecastDefaultExpiryId); waitForecastToFinish(job.getId(), forecastDefaultExpiryId);
waitForecastToFinish(job.getId(), forecastNoExpiryId); waitForecastToFinish(job.getId(), forecastNoExpiryId);
@ -166,8 +163,7 @@ public class DeleteExpiredDataIT extends MlNativeAutodetectIntegTestCase {
List<ForecastRequestStats> forecastStats = getForecastStats(); List<ForecastRequestStats> forecastStats = getForecastStats();
assertThat(forecastStats.size(), equalTo(getJobs().size() * 3)); assertThat(forecastStats.size(), equalTo(getJobs().size() * 3));
for (ForecastRequestStats forecastStat : forecastStats) { for (ForecastRequestStats forecastStat : forecastStats) {
assertThat(countForecastDocs(forecastStat.getJobId(), forecastStat.getForecastId()), assertThat(countForecastDocs(forecastStat.getJobId(), forecastStat.getForecastId()), equalTo(forecastStat.getRecordCount()));
equalTo((long) forecastStat.getRecordCount()));
} }
client().execute(DeleteExpiredDataAction.INSTANCE, new DeleteExpiredDataAction.Request()).get(); client().execute(DeleteExpiredDataAction.INSTANCE, new DeleteExpiredDataAction.Request()).get();
@ -213,11 +209,10 @@ public class DeleteExpiredDataIT extends MlNativeAutodetectIntegTestCase {
forecastStats = getForecastStats(); forecastStats = getForecastStats();
assertThat(forecastStats.size(), equalTo(getJobs().size() * 2)); assertThat(forecastStats.size(), equalTo(getJobs().size() * 2));
for (ForecastRequestStats forecastStat : forecastStats) { for (ForecastRequestStats forecastStat : forecastStats) {
assertThat(countForecastDocs(forecastStat.getJobId(), forecastStat.getForecastId()), assertThat(countForecastDocs(forecastStat.getJobId(), forecastStat.getForecastId()), equalTo(forecastStat.getRecordCount()));
equalTo((long) forecastStat.getRecordCount()));
} }
for (Job.Builder job : getJobs()) { for (Job.Builder job : getJobs()) {
for (long forecastId : shortExpiryForecastIds) { for (String forecastId : shortExpiryForecastIds) {
assertThat(countForecastDocs(job.getId(), forecastId), equalTo(0L)); assertThat(countForecastDocs(job.getId(), forecastId), equalTo(0L));
} }
} }

View File

@ -0,0 +1,143 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.ml.integration;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.ml.job.config.AnalysisConfig;
import org.elasticsearch.xpack.ml.job.config.DataDescription;
import org.elasticsearch.xpack.ml.job.config.Detector;
import org.elasticsearch.xpack.ml.job.config.Job;
import org.elasticsearch.xpack.ml.job.results.Bucket;
import org.elasticsearch.xpack.ml.job.results.Forecast;
import org.elasticsearch.xpack.ml.job.results.ForecastRequestStats;
import org.junit.After;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.closeTo;
import static org.hamcrest.Matchers.equalTo;
public class ForecastIT extends MlNativeAutodetectIntegTestCase {
@After
public void tearDownData() throws Exception {
cleanUp();
}
public void testSingleSeries() throws Exception {
Detector.Builder detector = new Detector.Builder("mean", "value");
TimeValue bucketSpan = TimeValue.timeValueHours(1);
AnalysisConfig.Builder analysisConfig = new AnalysisConfig.Builder(Collections.singletonList(detector.build()));
analysisConfig.setBucketSpan(bucketSpan);
DataDescription.Builder dataDescription = new DataDescription.Builder();
dataDescription.setTimeFormat("epoch");
Job.Builder job = new Job.Builder("forecast-it-test-single-series");
job.setAnalysisConfig(analysisConfig);
job.setDataDescription(dataDescription);
registerJob(job);
putJob(job);
openJob(job.getId());
long now = Instant.now().getEpochSecond();
long timestamp = now - 50 * bucketSpan.seconds();
List<String> data = new ArrayList<>();
while (timestamp < now) {
data.add(createJsonRecord(createRecord(timestamp, 10.0)));
data.add(createJsonRecord(createRecord(timestamp, 30.0)));
timestamp += bucketSpan.seconds();
}
postData(job.getId(), data.stream().collect(Collectors.joining()));
flushJob(job.getId(), false);
// Now we can start doing forecast requests
String forecastIdDefaultDurationDefaultExpiry = forecast(job.getId(), null, null);
String forecastIdDuration1HourNoExpiry = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
String forecastIdDuration3HoursExpiresIn24Hours = forecast(job.getId(), TimeValue.timeValueHours(3), TimeValue.timeValueHours(24));
waitForecastToFinish(job.getId(), forecastIdDefaultDurationDefaultExpiry);
waitForecastToFinish(job.getId(), forecastIdDuration1HourNoExpiry);
waitForecastToFinish(job.getId(), forecastIdDuration3HoursExpiresIn24Hours);
closeJob(job.getId());
List<Bucket> buckets = getBuckets(job.getId());
Bucket lastBucket = buckets.get(buckets.size() - 1);
long lastBucketTime = lastBucket.getTimestamp().getTime();
// Now let's verify forecasts
double expectedForecastValue = 20.0;
List<ForecastRequestStats> forecastStats = getForecastStats();
assertThat(forecastStats.size(), equalTo(3));
Map<String, ForecastRequestStats> idToForecastStats = new HashMap<>();
forecastStats.stream().forEach(f -> idToForecastStats.put(f.getForecastId(), f));
{
ForecastRequestStats forecastDefaultDurationDefaultExpiry = idToForecastStats.get(forecastIdDefaultDurationDefaultExpiry);
assertThat(forecastDefaultDurationDefaultExpiry.getExpiryTime().toEpochMilli(),
equalTo(forecastDefaultDurationDefaultExpiry.getCreateTime().toEpochMilli()
+ TimeValue.timeValueHours(14 * 24).getMillis()));
List<Forecast> forecasts = getForecasts(job.getId(), forecastDefaultDurationDefaultExpiry);
assertThat(forecastDefaultDurationDefaultExpiry.getRecordCount(), equalTo(24L));
assertThat(forecasts.size(), equalTo(24));
assertThat(forecasts.get(0).getTimestamp().getTime(), equalTo(lastBucketTime));
for (int i = 0; i < forecasts.size(); i++) {
Forecast forecast = forecasts.get(i);
assertThat(forecast.getTimestamp().getTime(), equalTo(lastBucketTime + i * bucketSpan.getMillis()));
assertThat(forecast.getBucketSpan(), equalTo(bucketSpan.getSeconds()));
assertThat(forecast.getForecastPrediction(), closeTo(expectedForecastValue, 0.01));
}
}
{
ForecastRequestStats forecastDuration1HourNoExpiry = idToForecastStats.get(forecastIdDuration1HourNoExpiry);
assertThat(forecastDuration1HourNoExpiry.getExpiryTime(), equalTo(Instant.EPOCH));
List<Forecast> forecasts = getForecasts(job.getId(), forecastDuration1HourNoExpiry);
assertThat(forecastDuration1HourNoExpiry.getRecordCount(), equalTo(1L));
assertThat(forecasts.size(), equalTo(1));
assertThat(forecasts.get(0).getTimestamp().getTime(), equalTo(lastBucketTime));
for (int i = 0; i < forecasts.size(); i++) {
Forecast forecast = forecasts.get(i);
assertThat(forecast.getTimestamp().getTime(), equalTo(lastBucketTime + i * bucketSpan.getMillis()));
assertThat(forecast.getBucketSpan(), equalTo(bucketSpan.getSeconds()));
assertThat(forecast.getForecastPrediction(), closeTo(expectedForecastValue, 0.01));
}
}
{
ForecastRequestStats forecastDuration3HoursExpiresIn24Hours = idToForecastStats.get(forecastIdDuration3HoursExpiresIn24Hours);
assertThat(forecastDuration3HoursExpiresIn24Hours.getExpiryTime().toEpochMilli(),
equalTo(forecastDuration3HoursExpiresIn24Hours.getCreateTime().toEpochMilli()
+ TimeValue.timeValueHours(24).getMillis()));
List<Forecast> forecasts = getForecasts(job.getId(), forecastDuration3HoursExpiresIn24Hours);
assertThat(forecastDuration3HoursExpiresIn24Hours.getRecordCount(), equalTo(3L));
assertThat(forecasts.size(), equalTo(3));
assertThat(forecasts.get(0).getTimestamp().getTime(), equalTo(lastBucketTime));
for (int i = 0; i < forecasts.size(); i++) {
Forecast forecast = forecasts.get(i);
assertThat(forecast.getTimestamp().getTime(), equalTo(lastBucketTime + i * bucketSpan.getMillis()));
assertThat(forecast.getBucketSpan(), equalTo(bucketSpan.getSeconds()));
assertThat(forecast.getForecastPrediction(), closeTo(expectedForecastValue, 0.01));
}
}
}
private static Map<String, Object> createRecord(long timestamp, double value) {
Map<String, Object> record = new HashMap<>();
record.put("time", timestamp);
record.put("value", value);
return record;
}
}

View File

@ -26,6 +26,8 @@ import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.SearchModule; import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.Task;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
@ -291,16 +293,18 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase {
return client().execute(PostDataAction.INSTANCE, request).actionGet().getDataCounts(); return client().execute(PostDataAction.INSTANCE, request).actionGet().getDataCounts();
} }
protected long forecast(String jobId, TimeValue duration, TimeValue expiresIn) { protected String forecast(String jobId, TimeValue duration, TimeValue expiresIn) {
ForecastJobAction.Request request = new ForecastJobAction.Request(jobId); ForecastJobAction.Request request = new ForecastJobAction.Request(jobId);
request.setDuration(duration.getStringRep()); if (duration != null) {
request.setDuration(duration.getStringRep());
}
if (expiresIn != null) { if (expiresIn != null) {
request.setExpiresIn(expiresIn.getStringRep()); request.setExpiresIn(expiresIn.getStringRep());
} }
return client().execute(ForecastJobAction.INSTANCE, request).actionGet().getForecastId(); return client().execute(ForecastJobAction.INSTANCE, request).actionGet().getForecastId();
} }
protected void waitForecastToFinish(String jobId, long forecastId) throws Exception { protected void waitForecastToFinish(String jobId, String forecastId) throws Exception {
assertBusy(() -> { assertBusy(() -> {
ForecastRequestStats forecastRequestStats = getForecastStats(jobId, forecastId); ForecastRequestStats forecastRequestStats = getForecastStats(jobId, forecastId);
assertThat(forecastRequestStats, is(notNullValue())); assertThat(forecastRequestStats, is(notNullValue()));
@ -308,7 +312,7 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase {
}, 30, TimeUnit.SECONDS); }, 30, TimeUnit.SECONDS);
} }
protected ForecastRequestStats getForecastStats(String jobId, long forecastId) { protected ForecastRequestStats getForecastStats(String jobId, String forecastId) {
SearchResponse searchResponse = client().prepareSearch(AnomalyDetectorsIndex.jobResultsAliasedName(jobId)) SearchResponse searchResponse = client().prepareSearch(AnomalyDetectorsIndex.jobResultsAliasedName(jobId))
.setQuery(QueryBuilders.boolQuery() .setQuery(QueryBuilders.boolQuery()
.filter(QueryBuilders.termQuery(Result.RESULT_TYPE.getPreferredName(), ForecastRequestStats.RESULT_TYPE_VALUE)) .filter(QueryBuilders.termQuery(Result.RESULT_TYPE.getPreferredName(), ForecastRequestStats.RESULT_TYPE_VALUE))
@ -350,7 +354,7 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase {
return forecastStats; return forecastStats;
} }
protected long countForecastDocs(String jobId, long forecastId) { protected long countForecastDocs(String jobId, String forecastId) {
SearchResponse searchResponse = client().prepareSearch(AnomalyDetectorsIndex.jobResultsIndexPrefix() + "*") SearchResponse searchResponse = client().prepareSearch(AnomalyDetectorsIndex.jobResultsIndexPrefix() + "*")
.setQuery(QueryBuilders.boolQuery() .setQuery(QueryBuilders.boolQuery()
.filter(QueryBuilders.termQuery(Result.RESULT_TYPE.getPreferredName(), Forecast.RESULT_TYPE_VALUE)) .filter(QueryBuilders.termQuery(Result.RESULT_TYPE.getPreferredName(), Forecast.RESULT_TYPE_VALUE))
@ -360,6 +364,30 @@ abstract class MlNativeAutodetectIntegTestCase extends SecurityIntegTestCase {
return searchResponse.getHits().getTotalHits(); return searchResponse.getHits().getTotalHits();
} }
protected List<Forecast> getForecasts(String jobId, ForecastRequestStats forecastRequestStats) {
List<Forecast> forecasts = new ArrayList<>();
SearchResponse searchResponse = client().prepareSearch(AnomalyDetectorsIndex.jobResultsIndexPrefix() + "*")
.setSize((int) forecastRequestStats.getRecordCount())
.setQuery(QueryBuilders.boolQuery()
.filter(QueryBuilders.termQuery(Result.RESULT_TYPE.getPreferredName(), Forecast.RESULT_TYPE_VALUE))
.filter(QueryBuilders.termQuery(Job.ID.getPreferredName(), jobId))
.filter(QueryBuilders.termQuery(Forecast.FORECAST_ID.getPreferredName(), forecastRequestStats.getForecastId())))
.addSort(SortBuilders.fieldSort(Result.TIMESTAMP.getPreferredName()).order(SortOrder.ASC))
.execute().actionGet();
SearchHits hits = searchResponse.getHits();
for (SearchHit hit : hits) {
try {
XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(
NamedXContentRegistry.EMPTY, hit.getSourceRef());
forecasts.add(Forecast.PARSER.apply(parser, null));
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
return forecasts;
}
@Override @Override
protected void ensureClusterStateConsistency() throws IOException { protected void ensureClusterStateConsistency() throws IOException {
if (cluster() != null && cluster().size() > 0) { if (cluster() != null && cluster().size() > 0) {

View File

@ -11,6 +11,10 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.ml.job.messages.Messages; import org.elasticsearch.xpack.ml.job.messages.Messages;
import java.util.HashSet;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.lessThanOrEqualTo;
@ -19,6 +23,14 @@ public class ForecastParamsTests extends ESTestCase {
private static ParseField END = new ParseField("end"); private static ParseField END = new ParseField("end");
private static ParseField DURATION = new ParseField("duration"); private static ParseField DURATION = new ParseField("duration");
public void testForecastIdsAreUnique() {
Set<String> ids = new HashSet<>();
for (int i = 0; i < 10; i++) {
ids.add(ForecastParams.builder().build().getForecastId());
}
assertThat(ids.size(), equalTo(10));
}
public void test_UnparseableEndTimeThrows() { public void test_UnparseableEndTimeThrows() {
ElasticsearchParseException e = ElasticsearchParseException e =
ESTestCase.expectThrows(ElasticsearchParseException.class, () -> ForecastParams.builder().endTime("bad", END).build()); ESTestCase.expectThrows(ElasticsearchParseException.class, () -> ForecastParams.builder().endTime("bad", END).build());

View File

@ -87,12 +87,12 @@ public class AutodetectResultTests extends AbstractSerializingTestCase<Autodetec
modelPlot = null; modelPlot = null;
} }
if (randomBoolean()) { if (randomBoolean()) {
forecast = new Forecast(jobId, randomNonNegativeLong(), new Date(randomLong()), randomNonNegativeLong(), randomInt()); forecast = new Forecast(jobId, randomAlphaOfLength(20), new Date(randomLong()), randomNonNegativeLong(), randomInt());
} else { } else {
forecast = null; forecast = null;
} }
if (randomBoolean()) { if (randomBoolean()) {
forecastRequestStats = new ForecastRequestStats(jobId, randomNonNegativeLong()); forecastRequestStats = new ForecastRequestStats(jobId, randomAlphaOfLength(20));
} else { } else {
forecastRequestStats = null; forecastRequestStats = null;
} }

View File

@ -24,10 +24,10 @@ public class ForecastRequestStatsTests extends AbstractSerializingTestCase<Forec
@Override @Override
protected ForecastRequestStats createTestInstance() { protected ForecastRequestStats createTestInstance() {
return createTestInstance("ForecastRequestStatsTest", randomNonNegativeLong()); return createTestInstance("ForecastRequestStatsTest", randomAlphaOfLength(20));
} }
public ForecastRequestStats createTestInstance(String jobId, long forecastId) { public ForecastRequestStats createTestInstance(String jobId, String forecastId) {
ForecastRequestStats forecastRequestStats = new ForecastRequestStats(jobId, forecastId); ForecastRequestStats forecastRequestStats = new ForecastRequestStats(jobId, forecastId);
if (randomBoolean()) { if (randomBoolean()) {
@ -45,10 +45,16 @@ public class ForecastRequestStatsTests extends AbstractSerializingTestCase<Forec
forecastRequestStats.setTimeStamp(Instant.ofEpochMilli(randomNonNegativeLong())); forecastRequestStats.setTimeStamp(Instant.ofEpochMilli(randomNonNegativeLong()));
} }
if (randomBoolean()) { if (randomBoolean()) {
forecastRequestStats.setEndTimeStamp(Instant.ofEpochMilli(randomNonNegativeLong())); forecastRequestStats.setStartTime(Instant.ofEpochMilli(randomNonNegativeLong()));
} }
if (randomBoolean()) { if (randomBoolean()) {
forecastRequestStats.setExpiryTimeStamp(Instant.ofEpochMilli(randomNonNegativeLong())); forecastRequestStats.setEndTime(Instant.ofEpochMilli(randomNonNegativeLong()));
}
if (randomBoolean()) {
forecastRequestStats.setCreateTime(Instant.ofEpochMilli(randomNonNegativeLong()));
}
if (randomBoolean()) {
forecastRequestStats.setExpiryTime(Instant.ofEpochMilli(randomNonNegativeLong()));
} }
if (randomBoolean()) { if (randomBoolean()) {
forecastRequestStats.setProgress(randomDouble()); forecastRequestStats.setProgress(randomDouble());

View File

@ -27,7 +27,7 @@ public class ForecastTests extends AbstractSerializingTestCase<Forecast> {
public Forecast createTestInstance(String jobId) { public Forecast createTestInstance(String jobId) {
Forecast forecast = Forecast forecast =
new Forecast(jobId, randomNonNegativeLong(), new Date(randomLong()), new Forecast(jobId, randomAlphaOfLength(20), new Date(randomLong()),
randomNonNegativeLong(), randomInt()); randomNonNegativeLong(), randomInt());
if (randomBoolean()) { if (randomBoolean()) {
@ -69,7 +69,7 @@ public class ForecastTests extends AbstractSerializingTestCase<Forecast> {
} }
public void testId() { public void testId() {
Forecast forecast = new Forecast("job-foo", 222, new Date(100L), 60L, 2); Forecast forecast = new Forecast("job-foo", "222", new Date(100L), 60L, 2);
String byFieldValue = null; String byFieldValue = null;
String partitionFieldValue = null; String partitionFieldValue = null;