This commit adjusts the following APIs so now they not only support an `_all` case, but wildcard patterned Ids as well. - `GET _ml/calendars/<calendar_id>/events` - `GET _ml/calendars/<calendar_id>` - `GET _ml/anomaly_detectors/<job_id>/model_snapshots/<snapshot_id>` - `DELETE _ml/anomaly_detectors/<job_id>/_forecast/<forecast_id>`
This commit is contained in:
parent
43ace5f80d
commit
0f142c6afc
|
@ -42,7 +42,7 @@ For more information, see
|
||||||
|
|
||||||
`<forecast_id>`::
|
`<forecast_id>`::
|
||||||
(Optional, string) A comma-separated list of forecast identifiers. If you do not
|
(Optional, string) A comma-separated list of forecast identifiers. If you do not
|
||||||
specify this optional parameter or if you specify `_all`, the API deletes all
|
specify this optional parameter or if you specify `_all` or `*` the API deletes all
|
||||||
forecasts from the job.
|
forecasts from the job.
|
||||||
|
|
||||||
`<job_id>`::
|
`<job_id>`::
|
||||||
|
|
|
@ -25,8 +25,10 @@ Retrieves information about the scheduled events in calendars.
|
||||||
[[ml-get-calendar-event-desc]]
|
[[ml-get-calendar-event-desc]]
|
||||||
== {api-description-title}
|
== {api-description-title}
|
||||||
|
|
||||||
You can get scheduled event information for a single calendar or for all
|
You can get scheduled event information for multiple calendars in a single
|
||||||
calendars by using `_all`.
|
API request by using a comma-separated list of ids or a wildcard expression.
|
||||||
|
You can get scheduled event information for all calendars by using `_all`,
|
||||||
|
by specifying `*` as the `<calendar_id>`, or by omitting the `<calendar_id>`.
|
||||||
|
|
||||||
For more information, see
|
For more information, see
|
||||||
{ml-docs}/ml-calendars.html[Calendars and scheduled events].
|
{ml-docs}/ml-calendars.html[Calendars and scheduled events].
|
||||||
|
|
|
@ -25,8 +25,10 @@ Retrieves configuration information for calendars.
|
||||||
[[ml-get-calendar-desc]]
|
[[ml-get-calendar-desc]]
|
||||||
== {api-description-title}
|
== {api-description-title}
|
||||||
|
|
||||||
You can get information for a single calendar or for all calendars by using
|
You can get information for multiple calendars in a single API request by using a
|
||||||
`_all`.
|
comma-separated list of ids or a wildcard expression. You can get
|
||||||
|
information for all calendars by using `_all`, by specifying `*` as the
|
||||||
|
`<calendar_id>`, or by omitting the `<calendar_id>`.
|
||||||
|
|
||||||
For more information, see
|
For more information, see
|
||||||
{ml-docs}/ml-calendars.html[Calendars and scheduled events].
|
{ml-docs}/ml-calendars.html[Calendars and scheduled events].
|
||||||
|
|
|
@ -34,8 +34,10 @@ include::{es-repo-dir}/ml/ml-shared.asciidoc[tag=job-id-anomaly-detection]
|
||||||
include::{es-repo-dir}/ml/ml-shared.asciidoc[tag=snapshot-id]
|
include::{es-repo-dir}/ml/ml-shared.asciidoc[tag=snapshot-id]
|
||||||
+
|
+
|
||||||
--
|
--
|
||||||
If you do not specify this optional parameter, the API returns information about
|
You can multiple snapshots for a single job in a single API request
|
||||||
all model snapshots.
|
by using a comma-separated list of `<snapshot_id>` or a wildcard expression.
|
||||||
|
You can get all snapshots for all calendars by using `_all`,
|
||||||
|
by specifying `*` as the `<snapshot_id>`, or by omitting the `<snapshot_id>`.
|
||||||
--
|
--
|
||||||
|
|
||||||
[[ml-get-snapshot-request-body]]
|
[[ml-get-snapshot-request-body]]
|
||||||
|
|
|
@ -128,7 +128,7 @@ public class GetCalendarEventsAction extends ActionType<GetCalendarEventsAction.
|
||||||
|
|
||||||
if (jobId != null && Strings.isAllOrWildcard(calendarId) == false) {
|
if (jobId != null && Strings.isAllOrWildcard(calendarId) == false) {
|
||||||
e = ValidateActions.addValidationError("If " + Job.ID.getPreferredName() + " is used " +
|
e = ValidateActions.addValidationError("If " + Job.ID.getPreferredName() + " is used " +
|
||||||
Calendar.ID.getPreferredName() + " must be '" + GetCalendarsAction.Request.ALL + "'", e);
|
Calendar.ID.getPreferredName() + " must be '" + GetCalendarsAction.Request.ALL + "' or '*'", e);
|
||||||
}
|
}
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class GetCalendarEventsActionRequestTests extends AbstractSerializingTest
|
||||||
|
|
||||||
ActionRequestValidationException validationException = request.validate();
|
ActionRequestValidationException validationException = request.validate();
|
||||||
assertNotNull(validationException);
|
assertNotNull(validationException);
|
||||||
assertEquals("Validation Failed: 1: If job_id is used calendar_id must be '_all';", validationException.getMessage());
|
assertEquals("Validation Failed: 1: If job_id is used calendar_id must be '_all' or '*';", validationException.getMessage());
|
||||||
|
|
||||||
request = new GetCalendarEventsAction.Request("_all");
|
request = new GetCalendarEventsAction.Request("_all");
|
||||||
request.setJobId("foo");
|
request.setJobId("foo");
|
||||||
|
|
|
@ -187,7 +187,7 @@ public class ForecastIT extends MlNativeAutodetectIntegTestCase {
|
||||||
equalTo("Cannot run forecast: Forecast cannot be executed as job requires data to have been processed and modeled"));
|
equalTo("Cannot run forecast: Forecast cannot be executed as job requires data to have been processed and modeled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMemoryStatus() throws Exception {
|
public void testMemoryStatus() {
|
||||||
Detector.Builder detector = new Detector.Builder("mean", "value");
|
Detector.Builder detector = new Detector.Builder("mean", "value");
|
||||||
detector.setByFieldName("clientIP");
|
detector.setByFieldName("clientIP");
|
||||||
|
|
||||||
|
@ -287,6 +287,74 @@ public class ForecastIT extends MlNativeAutodetectIntegTestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testDeleteWildCard() 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-delete-wildcard");
|
||||||
|
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);
|
||||||
|
String forecastIdDefaultDurationDefaultExpiry = forecast(job.getId(), null, null);
|
||||||
|
String forecastIdDuration1HourNoExpiry = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
|
||||||
|
String forecastId2Duration1HourNoExpiry = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
|
||||||
|
String forecastId2Duration1HourNoExpiry2 = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
|
||||||
|
waitForecastToFinish(job.getId(), forecastIdDefaultDurationDefaultExpiry);
|
||||||
|
waitForecastToFinish(job.getId(), forecastIdDuration1HourNoExpiry);
|
||||||
|
waitForecastToFinish(job.getId(), forecastId2Duration1HourNoExpiry);
|
||||||
|
waitForecastToFinish(job.getId(), forecastId2Duration1HourNoExpiry2);
|
||||||
|
closeJob(job.getId());
|
||||||
|
|
||||||
|
assertNotNull(getForecastStats(job.getId(), forecastIdDefaultDurationDefaultExpiry));
|
||||||
|
assertNotNull(getForecastStats(job.getId(), forecastIdDuration1HourNoExpiry));
|
||||||
|
assertNotNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry));
|
||||||
|
assertNotNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry2));
|
||||||
|
|
||||||
|
{
|
||||||
|
DeleteForecastAction.Request request = new DeleteForecastAction.Request(job.getId(),
|
||||||
|
forecastIdDefaultDurationDefaultExpiry.substring(0, forecastIdDefaultDurationDefaultExpiry.length() - 2) + "*"
|
||||||
|
+ ","
|
||||||
|
+ forecastIdDuration1HourNoExpiry);
|
||||||
|
AcknowledgedResponse response = client().execute(DeleteForecastAction.INSTANCE, request).actionGet();
|
||||||
|
assertTrue(response.isAcknowledged());
|
||||||
|
|
||||||
|
assertNull(getForecastStats(job.getId(), forecastIdDefaultDurationDefaultExpiry));
|
||||||
|
assertNull(getForecastStats(job.getId(), forecastIdDuration1HourNoExpiry));
|
||||||
|
assertNotNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry));
|
||||||
|
assertNotNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry2));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DeleteForecastAction.Request request = new DeleteForecastAction.Request(job.getId(), "*");
|
||||||
|
AcknowledgedResponse response = client().execute(DeleteForecastAction.INSTANCE, request).actionGet();
|
||||||
|
assertTrue(response.isAcknowledged());
|
||||||
|
|
||||||
|
assertNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry));
|
||||||
|
assertNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry2));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void testDelete() throws Exception {
|
public void testDelete() throws Exception {
|
||||||
Detector.Builder detector = new Detector.Builder("mean", "value");
|
Detector.Builder detector = new Detector.Builder("mean", "value");
|
||||||
|
|
||||||
|
@ -317,6 +385,8 @@ public class ForecastIT extends MlNativeAutodetectIntegTestCase {
|
||||||
flushJob(job.getId(), false);
|
flushJob(job.getId(), false);
|
||||||
String forecastIdDefaultDurationDefaultExpiry = forecast(job.getId(), null, null);
|
String forecastIdDefaultDurationDefaultExpiry = forecast(job.getId(), null, null);
|
||||||
String forecastIdDuration1HourNoExpiry = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
|
String forecastIdDuration1HourNoExpiry = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
|
||||||
|
String forecastId2Duration1HourNoExpiry = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
|
||||||
|
String forecastId2Duration1HourNoExpiry2 = forecast(job.getId(), TimeValue.timeValueHours(1), TimeValue.ZERO);
|
||||||
waitForecastToFinish(job.getId(), forecastIdDefaultDurationDefaultExpiry);
|
waitForecastToFinish(job.getId(), forecastIdDefaultDurationDefaultExpiry);
|
||||||
waitForecastToFinish(job.getId(), forecastIdDuration1HourNoExpiry);
|
waitForecastToFinish(job.getId(), forecastIdDuration1HourNoExpiry);
|
||||||
closeJob(job.getId());
|
closeJob(job.getId());
|
||||||
|
@ -333,13 +403,11 @@ public class ForecastIT extends MlNativeAutodetectIntegTestCase {
|
||||||
forecastIdDefaultDurationDefaultExpiry + "," + forecastIdDuration1HourNoExpiry);
|
forecastIdDefaultDurationDefaultExpiry + "," + forecastIdDuration1HourNoExpiry);
|
||||||
AcknowledgedResponse response = client().execute(DeleteForecastAction.INSTANCE, request).actionGet();
|
AcknowledgedResponse response = client().execute(DeleteForecastAction.INSTANCE, request).actionGet();
|
||||||
assertTrue(response.isAcknowledged());
|
assertTrue(response.isAcknowledged());
|
||||||
}
|
|
||||||
|
|
||||||
{
|
assertNull(getForecastStats(job.getId(), forecastIdDefaultDurationDefaultExpiry));
|
||||||
ForecastRequestStats forecastStats = getForecastStats(job.getId(), forecastIdDefaultDurationDefaultExpiry);
|
assertNull(getForecastStats(job.getId(), forecastIdDuration1HourNoExpiry));
|
||||||
assertNull(forecastStats);
|
assertNotNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry));
|
||||||
ForecastRequestStats otherStats = getForecastStats(job.getId(), forecastIdDuration1HourNoExpiry);
|
assertNotNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry2));
|
||||||
assertNull(otherStats);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -354,6 +422,9 @@ public class ForecastIT extends MlNativeAutodetectIntegTestCase {
|
||||||
DeleteForecastAction.Request request = new DeleteForecastAction.Request(job.getId(), Metadata.ALL);
|
DeleteForecastAction.Request request = new DeleteForecastAction.Request(job.getId(), Metadata.ALL);
|
||||||
AcknowledgedResponse response = client().execute(DeleteForecastAction.INSTANCE, request).actionGet();
|
AcknowledgedResponse response = client().execute(DeleteForecastAction.INSTANCE, request).actionGet();
|
||||||
assertTrue(response.isAcknowledged());
|
assertTrue(response.isAcknowledged());
|
||||||
|
|
||||||
|
assertNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry));
|
||||||
|
assertNull(getForecastStats(job.getId(), forecastId2Duration1HourNoExpiry2));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
|
||||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||||
import org.elasticsearch.action.bulk.BulkResponse;
|
import org.elasticsearch.action.bulk.BulkResponse;
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.support.PlainActionFuture;
|
||||||
import org.elasticsearch.action.support.WriteRequest;
|
import org.elasticsearch.action.support.WriteRequest;
|
||||||
import org.elasticsearch.client.OriginSettingClient;
|
import org.elasticsearch.client.OriginSettingClient;
|
||||||
import org.elasticsearch.cluster.metadata.AliasMetadata;
|
import org.elasticsearch.cluster.metadata.AliasMetadata;
|
||||||
|
@ -37,6 +38,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.xpack.core.ClientHelper;
|
import org.elasticsearch.xpack.core.ClientHelper;
|
||||||
|
import org.elasticsearch.xpack.core.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.core.action.util.QueryPage;
|
import org.elasticsearch.xpack.core.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.core.ml.MlMetaIndex;
|
import org.elasticsearch.xpack.core.ml.MlMetaIndex;
|
||||||
import org.elasticsearch.xpack.core.ml.MlMetadata;
|
import org.elasticsearch.xpack.core.ml.MlMetadata;
|
||||||
|
@ -72,6 +74,7 @@ import org.elasticsearch.xpack.ml.utils.persistence.ResultsPersisterService;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -255,21 +258,69 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
calendars.add(new Calendar("cat foo calendar", Arrays.asList("cat", "foo"), null));
|
calendars.add(new Calendar("cat foo calendar", Arrays.asList("cat", "foo"), null));
|
||||||
indexCalendars(calendars);
|
indexCalendars(calendars);
|
||||||
|
|
||||||
List<Calendar> queryResult = getCalendars("ted");
|
List<Calendar> queryResult = getCalendars(CalendarQueryBuilder.builder().jobId("ted"));
|
||||||
assertThat(queryResult, is(empty()));
|
assertThat(queryResult, is(empty()));
|
||||||
|
|
||||||
queryResult = getCalendars("foo");
|
queryResult = getCalendars(CalendarQueryBuilder.builder().jobId("foo"));
|
||||||
assertThat(queryResult, hasSize(3));
|
assertThat(queryResult, hasSize(3));
|
||||||
Long matchedCount = queryResult.stream().filter(
|
Long matchedCount = queryResult.stream().filter(
|
||||||
c -> c.getId().equals("foo calendar") || c.getId().equals("foo bar calendar") || c.getId().equals("cat foo calendar"))
|
c -> c.getId().equals("foo calendar") || c.getId().equals("foo bar calendar") || c.getId().equals("cat foo calendar"))
|
||||||
.count();
|
.count();
|
||||||
assertEquals(Long.valueOf(3), matchedCount);
|
assertEquals(Long.valueOf(3), matchedCount);
|
||||||
|
|
||||||
queryResult = getCalendars("bar");
|
queryResult = getCalendars(CalendarQueryBuilder.builder().jobId("bar"));
|
||||||
assertThat(queryResult, hasSize(1));
|
assertThat(queryResult, hasSize(1));
|
||||||
assertEquals("foo bar calendar", queryResult.get(0).getId());
|
assertEquals("foo bar calendar", queryResult.get(0).getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGetCalandarById() throws Exception {
|
||||||
|
List<Calendar> calendars = new ArrayList<>();
|
||||||
|
calendars.add(new Calendar("empty calendar", Collections.emptyList(), null));
|
||||||
|
calendars.add(new Calendar("foo calendar", Collections.singletonList("foo"), null));
|
||||||
|
calendars.add(new Calendar("foo bar calendar", Arrays.asList("foo", "bar"), null));
|
||||||
|
calendars.add(new Calendar("cat calendar", Collections.singletonList("cat"), null));
|
||||||
|
calendars.add(new Calendar("cat foo calendar", Arrays.asList("cat", "foo"), null));
|
||||||
|
indexCalendars(calendars);
|
||||||
|
|
||||||
|
List<Calendar> queryResult = getCalendars(CalendarQueryBuilder.builder()
|
||||||
|
.calendarIdTokens(new String[]{"foo*"})
|
||||||
|
.sort(true));
|
||||||
|
assertThat(queryResult, hasSize(2));
|
||||||
|
assertThat(queryResult.get(0).getId(), equalTo("foo bar calendar"));
|
||||||
|
assertThat(queryResult.get(1).getId(), equalTo("foo calendar"));
|
||||||
|
|
||||||
|
queryResult = getCalendars(CalendarQueryBuilder.builder()
|
||||||
|
.calendarIdTokens(new String[]{"foo calendar", "cat calendar"})
|
||||||
|
.sort(true));
|
||||||
|
assertThat(queryResult, hasSize(2));
|
||||||
|
assertThat(queryResult.get(0).getId(), equalTo("cat calendar"));
|
||||||
|
assertThat(queryResult.get(1).getId(), equalTo("foo calendar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetCalendarByIdAndPaging() throws Exception {
|
||||||
|
List<Calendar> calendars = new ArrayList<>();
|
||||||
|
calendars.add(new Calendar("empty calendar", Collections.emptyList(), null));
|
||||||
|
calendars.add(new Calendar("foo calendar", Collections.singletonList("foo"), null));
|
||||||
|
calendars.add(new Calendar("foo bar calendar", Arrays.asList("foo", "bar"), null));
|
||||||
|
calendars.add(new Calendar("cat calendar", Collections.singletonList("cat"), null));
|
||||||
|
calendars.add(new Calendar("cat foo calendar", Arrays.asList("cat", "foo"), null));
|
||||||
|
indexCalendars(calendars);
|
||||||
|
|
||||||
|
List<Calendar> queryResult = getCalendars(CalendarQueryBuilder.builder()
|
||||||
|
.calendarIdTokens(new String[]{"foo*"})
|
||||||
|
.pageParams(new PageParams(0, 1))
|
||||||
|
.sort(true));
|
||||||
|
assertThat(queryResult, hasSize(1));
|
||||||
|
assertThat(queryResult.get(0).getId(), equalTo("foo bar calendar"));
|
||||||
|
|
||||||
|
queryResult = getCalendars(CalendarQueryBuilder.builder()
|
||||||
|
.calendarIdTokens(new String[]{"foo calendar", "cat calendar"})
|
||||||
|
.sort(true)
|
||||||
|
.pageParams(new PageParams(1, 1)));
|
||||||
|
assertThat(queryResult, hasSize(1));
|
||||||
|
assertThat(queryResult.get(0).getId(), equalTo("foo calendar"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testUpdateCalendar() throws Exception {
|
public void testUpdateCalendar() throws Exception {
|
||||||
MlMetadata.Builder mlBuilder = new MlMetadata.Builder();
|
MlMetadata.Builder mlBuilder = new MlMetadata.Builder();
|
||||||
mlBuilder.putJob(createJob("foo").build(), false);
|
mlBuilder.putJob(createJob("foo").build(), false);
|
||||||
|
@ -319,7 +370,7 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
throw exceptionHolder.get();
|
throw exceptionHolder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Calendar> updatedCalendars = getCalendars(null);
|
List<Calendar> updatedCalendars = getCalendars(CalendarQueryBuilder.builder());
|
||||||
assertEquals(5, updatedCalendars.size());
|
assertEquals(5, updatedCalendars.size());
|
||||||
for (Calendar cal: updatedCalendars) {
|
for (Calendar cal: updatedCalendars) {
|
||||||
assertThat("bar", is(not(in(cal.getJobIds()))));
|
assertThat("bar", is(not(in(cal.getJobIds()))));
|
||||||
|
@ -341,7 +392,7 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
throw exceptionHolder.get();
|
throw exceptionHolder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
updatedCalendars = getCalendars(null);
|
updatedCalendars = getCalendars(CalendarQueryBuilder.builder());
|
||||||
assertEquals(5, updatedCalendars.size());
|
assertEquals(5, updatedCalendars.size());
|
||||||
for (Calendar cal: updatedCalendars) {
|
for (Calendar cal: updatedCalendars) {
|
||||||
assertThat("bar", is(not(in(cal.getJobIds()))));
|
assertThat("bar", is(not(in(cal.getJobIds()))));
|
||||||
|
@ -384,16 +435,11 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
return aliasMetadataList.stream().map(AliasMetadata::alias).collect(Collectors.toSet());
|
return aliasMetadataList.stream().map(AliasMetadata::alias).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Calendar> getCalendars(String jobId) throws Exception {
|
private List<Calendar> getCalendars(CalendarQueryBuilder query) throws Exception {
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
|
AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
|
||||||
AtomicReference<QueryPage<Calendar>> result = new AtomicReference<>();
|
AtomicReference<QueryPage<Calendar>> result = new AtomicReference<>();
|
||||||
|
|
||||||
CalendarQueryBuilder query = new CalendarQueryBuilder();
|
|
||||||
|
|
||||||
if (jobId != null) {
|
|
||||||
query.jobId(jobId);
|
|
||||||
}
|
|
||||||
jobProvider.calendars(query, ActionListener.wrap(
|
jobProvider.calendars(query, ActionListener.wrap(
|
||||||
r -> {
|
r -> {
|
||||||
result.set(r);
|
result.set(r);
|
||||||
|
@ -455,7 +501,7 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
return calendarHolder.get();
|
return calendarHolder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testScheduledEvents() throws Exception {
|
public void testScheduledEventsForJobs() throws Exception {
|
||||||
Job.Builder jobA = createJob("job_a");
|
Job.Builder jobA = createJob("job_a");
|
||||||
Job.Builder jobB = createJob("job_b");
|
Job.Builder jobB = createJob("job_b");
|
||||||
Job.Builder jobC = createJob("job_c");
|
Job.Builder jobC = createJob("job_c");
|
||||||
|
@ -504,6 +550,59 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
assertEquals(events.get(3), returnedEvents.get(1));
|
assertEquals(events.get(3), returnedEvents.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testScheduledEvents() throws Exception {
|
||||||
|
createJob("job_a");
|
||||||
|
createJob("job_b");
|
||||||
|
createJob("job_c");
|
||||||
|
|
||||||
|
String calendarAId = "maintenance_a";
|
||||||
|
List<Calendar> calendars = new ArrayList<>();
|
||||||
|
calendars.add(new Calendar(calendarAId, Collections.singletonList("job_a"), null));
|
||||||
|
|
||||||
|
ZonedDateTime now = ZonedDateTime.now();
|
||||||
|
List<ScheduledEvent> events = new ArrayList<>();
|
||||||
|
events.add(buildScheduledEvent("downtime", now.plusDays(1), now.plusDays(2), calendarAId));
|
||||||
|
events.add(buildScheduledEvent("downtime_AA", now.plusDays(8), now.plusDays(9), calendarAId));
|
||||||
|
events.add(buildScheduledEvent("downtime_AAA", now.plusDays(15), now.plusDays(16), calendarAId));
|
||||||
|
|
||||||
|
String calendarABId = "maintenance_a_and_b";
|
||||||
|
calendars.add(new Calendar(calendarABId, Arrays.asList("job_a", "job_b"), null));
|
||||||
|
|
||||||
|
events.add(buildScheduledEvent("downtime_AB", now.plusDays(12), now.plusDays(13), calendarABId));
|
||||||
|
|
||||||
|
indexCalendars(calendars);
|
||||||
|
indexScheduledEvents(events);
|
||||||
|
|
||||||
|
List<ScheduledEvent> returnedEvents = getScheduledEvents(new ScheduledEventsQueryBuilder());
|
||||||
|
assertEquals(4, returnedEvents.size());
|
||||||
|
assertEquals(events.get(0), returnedEvents.get(0));
|
||||||
|
assertEquals(events.get(1), returnedEvents.get(1));
|
||||||
|
assertEquals(events.get(3), returnedEvents.get(2));
|
||||||
|
assertEquals(events.get(2), returnedEvents.get(3));
|
||||||
|
|
||||||
|
returnedEvents = getScheduledEvents(ScheduledEventsQueryBuilder.builder().calendarIds(new String[]{"maintenance_a"}));
|
||||||
|
assertEquals(3, returnedEvents.size());
|
||||||
|
assertEquals(events.get(0), returnedEvents.get(0));
|
||||||
|
assertEquals(events.get(1), returnedEvents.get(1));
|
||||||
|
assertEquals(events.get(2), returnedEvents.get(2));
|
||||||
|
|
||||||
|
returnedEvents = getScheduledEvents(ScheduledEventsQueryBuilder.builder()
|
||||||
|
.calendarIds(new String[]{"maintenance_a", "maintenance_a_and_b"}));
|
||||||
|
assertEquals(4, returnedEvents.size());
|
||||||
|
assertEquals(events.get(0), returnedEvents.get(0));
|
||||||
|
assertEquals(events.get(1), returnedEvents.get(1));
|
||||||
|
assertEquals(events.get(3), returnedEvents.get(2));
|
||||||
|
assertEquals(events.get(2), returnedEvents.get(3));
|
||||||
|
|
||||||
|
returnedEvents = getScheduledEvents(ScheduledEventsQueryBuilder.builder()
|
||||||
|
.calendarIds(new String[]{"maintenance_a*"}));
|
||||||
|
assertEquals(4, returnedEvents.size());
|
||||||
|
assertEquals(events.get(0), returnedEvents.get(0));
|
||||||
|
assertEquals(events.get(1), returnedEvents.get(1));
|
||||||
|
assertEquals(events.get(3), returnedEvents.get(2));
|
||||||
|
assertEquals(events.get(2), returnedEvents.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
public void testScheduledEventsForJob_withGroup() throws Exception {
|
public void testScheduledEventsForJob_withGroup() throws Exception {
|
||||||
String groupA = "group-a";
|
String groupA = "group-a";
|
||||||
String groupB = "group-b";
|
String groupB = "group-b";
|
||||||
|
@ -545,6 +644,49 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testGetSnapshots() {
|
||||||
|
String jobId = "test_get_snapshots";
|
||||||
|
Job.Builder job = createJob(jobId);
|
||||||
|
indexModelSnapshot(new ModelSnapshot.Builder(jobId).setSnapshotId("snap_2")
|
||||||
|
.setTimestamp(Date.from(Instant.ofEpochMilli(10)))
|
||||||
|
.build());
|
||||||
|
indexModelSnapshot(new ModelSnapshot.Builder(jobId).setSnapshotId("snap_1")
|
||||||
|
.setTimestamp(Date.from(Instant.ofEpochMilli(11)))
|
||||||
|
.build());
|
||||||
|
indexModelSnapshot(new ModelSnapshot.Builder(jobId).setSnapshotId("other_snap")
|
||||||
|
.setTimestamp(Date.from(Instant.ofEpochMilli(12)))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
client().admin().indices().prepareRefresh(AnomalyDetectorsIndex.jobStateIndexPattern(),
|
||||||
|
AnomalyDetectorsIndex.jobResultsAliasedName(jobId)).get();
|
||||||
|
|
||||||
|
PlainActionFuture<QueryPage<ModelSnapshot>> future = new PlainActionFuture<>();
|
||||||
|
jobProvider.modelSnapshots(jobId, 0, 4, "9", "15", "", false, "snap_2,snap_1", future::onResponse, future::onFailure);
|
||||||
|
List<ModelSnapshot> snapshots = future.actionGet().results();
|
||||||
|
assertThat(snapshots.get(0).getSnapshotId(), equalTo("snap_2"));
|
||||||
|
assertThat(snapshots.get(1).getSnapshotId(), equalTo("snap_1"));
|
||||||
|
|
||||||
|
future = new PlainActionFuture<>();
|
||||||
|
jobProvider.modelSnapshots(jobId, 0, 4, "9", "15", "", false, "snap_*", future::onResponse, future::onFailure);
|
||||||
|
snapshots = future.actionGet().results();
|
||||||
|
assertThat(snapshots.get(0).getSnapshotId(), equalTo("snap_2"));
|
||||||
|
assertThat(snapshots.get(1).getSnapshotId(), equalTo("snap_1"));
|
||||||
|
|
||||||
|
future = new PlainActionFuture<>();
|
||||||
|
jobProvider.modelSnapshots(jobId, 0, 4, "9", "15", "", false, "snap_*,other_snap", future::onResponse, future::onFailure);
|
||||||
|
snapshots = future.actionGet().results();
|
||||||
|
assertThat(snapshots.get(0).getSnapshotId(), equalTo("snap_2"));
|
||||||
|
assertThat(snapshots.get(1).getSnapshotId(), equalTo("snap_1"));
|
||||||
|
assertThat(snapshots.get(2).getSnapshotId(), equalTo("other_snap"));
|
||||||
|
|
||||||
|
future = new PlainActionFuture<>();
|
||||||
|
jobProvider.modelSnapshots(jobId, 0, 4, "9", "15", "", false, "*", future::onResponse, future::onFailure);
|
||||||
|
snapshots = future.actionGet().results();
|
||||||
|
assertThat(snapshots.get(0).getSnapshotId(), equalTo("snap_2"));
|
||||||
|
assertThat(snapshots.get(1).getSnapshotId(), equalTo("snap_1"));
|
||||||
|
assertThat(snapshots.get(2).getSnapshotId(), equalTo("other_snap"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testGetAutodetectParams() throws Exception {
|
public void testGetAutodetectParams() throws Exception {
|
||||||
String jobId = "test_get_autodetect_params";
|
String jobId = "test_get_autodetect_params";
|
||||||
Job.Builder job = createJob(jobId, Arrays.asList("fruit", "tea"));
|
Job.Builder job = createJob(jobId, Arrays.asList("fruit", "tea"));
|
||||||
|
@ -664,6 +806,27 @@ public class JobResultsProviderIT extends MlSingleNodeTestCase {
|
||||||
return searchResultHolder.get().results();
|
return searchResultHolder.get().results();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ScheduledEvent> getScheduledEvents(ScheduledEventsQueryBuilder query) throws Exception {
|
||||||
|
AtomicReference<Exception> errorHolder = new AtomicReference<>();
|
||||||
|
AtomicReference<QueryPage<ScheduledEvent>> searchResultHolder = new AtomicReference<>();
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
jobProvider.scheduledEvents(query, ActionListener.wrap(
|
||||||
|
params -> {
|
||||||
|
searchResultHolder.set(params);
|
||||||
|
latch.countDown();
|
||||||
|
}, e -> {
|
||||||
|
errorHolder.set(e);
|
||||||
|
latch.countDown();
|
||||||
|
}));
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
if (errorHolder.get() != null) {
|
||||||
|
throw errorHolder.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return searchResultHolder.get().results();
|
||||||
|
}
|
||||||
|
|
||||||
private Job.Builder createJob(String jobId) {
|
private Job.Builder createJob(String jobId) {
|
||||||
return createJob(jobId, Collections.emptyList());
|
return createJob(jobId, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,11 +54,11 @@ import org.elasticsearch.xpack.core.ml.job.results.ForecastRequestStats;
|
||||||
import org.elasticsearch.xpack.core.ml.job.results.ForecastRequestStats.ForecastRequestStatus;
|
import org.elasticsearch.xpack.core.ml.job.results.ForecastRequestStats.ForecastRequestStatus;
|
||||||
import org.elasticsearch.xpack.core.ml.job.results.Result;
|
import org.elasticsearch.xpack.core.ml.job.results.Result;
|
||||||
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.QueryBuilderHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -96,22 +96,21 @@ public class TransportDeleteForecastAction extends HandledTransportAction<Delete
|
||||||
protected void doExecute(Task task, DeleteForecastAction.Request request, ActionListener<AcknowledgedResponse> listener) {
|
protected void doExecute(Task task, DeleteForecastAction.Request request, ActionListener<AcknowledgedResponse> listener) {
|
||||||
final String jobId = request.getJobId();
|
final String jobId = request.getJobId();
|
||||||
|
|
||||||
String forecastsExpression = request.getForecastId();
|
final String forecastsExpression = request.getForecastId();
|
||||||
final String[] forecastIds = Strings.tokenizeToStringArray(forecastsExpression, ",");
|
final String[] forecastIds = Strings.splitStringByCommaToArray(forecastsExpression);
|
||||||
|
|
||||||
ActionListener<SearchResponse> forecastStatsHandler = ActionListener.wrap(
|
ActionListener<SearchResponse> forecastStatsHandler = ActionListener.wrap(
|
||||||
searchResponse -> deleteForecasts(searchResponse, request, listener),
|
searchResponse -> deleteForecasts(searchResponse, request, listener),
|
||||||
e -> listener.onFailure(new ElasticsearchException("An error occurred while searching forecasts to delete", e)));
|
e -> listener.onFailure(new ElasticsearchException("An error occurred while searching forecasts to delete", e)));
|
||||||
|
|
||||||
SearchSourceBuilder source = new SearchSourceBuilder();
|
SearchSourceBuilder source = new SearchSourceBuilder();
|
||||||
|
|
||||||
BoolQueryBuilder builder = QueryBuilders.boolQuery();
|
BoolQueryBuilder builder = QueryBuilders.boolQuery()
|
||||||
BoolQueryBuilder innerBool = QueryBuilders.boolQuery().must(
|
.filter(QueryBuilders.termQuery(Result.RESULT_TYPE.getPreferredName(), ForecastRequestStats.RESULT_TYPE_VALUE));
|
||||||
QueryBuilders.termQuery(Result.RESULT_TYPE.getPreferredName(), ForecastRequestStats.RESULT_TYPE_VALUE));
|
QueryBuilderHelper
|
||||||
if (Strings.isAllOrWildcard(forecastIds) == false) {
|
.buildTokenFilterQuery(Forecast.FORECAST_ID.getPreferredName(), forecastIds)
|
||||||
innerBool.must(QueryBuilders.termsQuery(Forecast.FORECAST_ID.getPreferredName(), new HashSet<>(Arrays.asList(forecastIds))));
|
.ifPresent(builder::filter);
|
||||||
}
|
source.query(builder);
|
||||||
|
|
||||||
source.query(builder.filter(innerBool));
|
|
||||||
|
|
||||||
SearchRequest searchRequest = new SearchRequest(AnomalyDetectorsIndex.jobResultsAliasedName(jobId));
|
SearchRequest searchRequest = new SearchRequest(AnomalyDetectorsIndex.jobResultsAliasedName(jobId));
|
||||||
searchRequest.source(source);
|
searchRequest.source(source);
|
||||||
|
@ -143,7 +142,7 @@ public class TransportDeleteForecastAction extends HandledTransportAction<Delete
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forecastsToDelete.isEmpty()) {
|
if (forecastsToDelete.isEmpty()) {
|
||||||
if (Strings.isAllOrWildcard(new String[]{request.getForecastId()}) &&
|
if (Strings.isAllOrWildcard(request.getForecastId()) &&
|
||||||
request.isAllowNoForecasts()) {
|
request.isAllowNoForecasts()) {
|
||||||
listener.onResponse(new AcknowledgedResponse(true));
|
listener.onResponse(new AcknowledgedResponse(true));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
import org.elasticsearch.ResourceNotFoundException;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
|
@ -90,7 +91,7 @@ public class TransportDeleteModelSnapshotAction extends HandledTransportAction<D
|
||||||
deleteCandidate.getSnapshotId(), deleteCandidate.getDescription());
|
deleteCandidate.getSnapshotId(), deleteCandidate.getDescription());
|
||||||
|
|
||||||
auditor.info(request.getJobId(), msg);
|
auditor.info(request.getJobId(), msg);
|
||||||
logger.debug("[{}] {}", request.getJobId(), msg);
|
logger.debug(() -> new ParameterizedMessage("[{}] {}", request.getJobId(), msg));
|
||||||
// We don't care about the bulk response, just that it succeeded
|
// We don't care about the bulk response, just that it succeeded
|
||||||
listener.onResponse(new AcknowledgedResponse(true));
|
listener.onResponse(new AcknowledgedResponse(true));
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.xpack.core.ml.action.GetCalendarEventsAction;
|
||||||
import org.elasticsearch.xpack.core.ml.calendars.ScheduledEvent;
|
import org.elasticsearch.xpack.core.ml.calendars.ScheduledEvent;
|
||||||
import org.elasticsearch.xpack.core.ml.job.config.Job;
|
import org.elasticsearch.xpack.core.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.xpack.ml.job.persistence.CalendarQueryBuilder;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobConfigProvider;
|
import org.elasticsearch.xpack.ml.job.persistence.JobConfigProvider;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobResultsProvider;
|
import org.elasticsearch.xpack.ml.job.persistence.JobResultsProvider;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.ScheduledEventsQueryBuilder;
|
import org.elasticsearch.xpack.ml.job.persistence.ScheduledEventsQueryBuilder;
|
||||||
|
@ -41,17 +42,15 @@ public class TransportGetCalendarEventsAction extends HandledTransportAction<Get
|
||||||
@Override
|
@Override
|
||||||
protected void doExecute(Task task, GetCalendarEventsAction.Request request,
|
protected void doExecute(Task task, GetCalendarEventsAction.Request request,
|
||||||
ActionListener<GetCalendarEventsAction.Response> listener) {
|
ActionListener<GetCalendarEventsAction.Response> listener) {
|
||||||
|
final String[] calendarId = Strings.splitStringByCommaToArray(request.getCalendarId());
|
||||||
ActionListener<Boolean> calendarExistsListener = ActionListener.wrap(
|
ActionListener<Boolean> calendarExistsListener = ActionListener.wrap(
|
||||||
r -> {
|
r -> {
|
||||||
ScheduledEventsQueryBuilder query = new ScheduledEventsQueryBuilder()
|
ScheduledEventsQueryBuilder query = new ScheduledEventsQueryBuilder()
|
||||||
.start(request.getStart())
|
.start(request.getStart())
|
||||||
.end(request.getEnd())
|
.end(request.getEnd())
|
||||||
.from(request.getPageParams().getFrom())
|
.from(request.getPageParams().getFrom())
|
||||||
.size(request.getPageParams().getSize());
|
.size(request.getPageParams().getSize())
|
||||||
|
.calendarIds(calendarId);
|
||||||
if (Strings.isAllOrWildcard(request.getCalendarId()) == false) {
|
|
||||||
query.calendarIds(Collections.singletonList(request.getCalendarId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionListener<QueryPage<ScheduledEvent>> eventsListener = ActionListener.wrap(
|
ActionListener<QueryPage<ScheduledEvent>> eventsListener = ActionListener.wrap(
|
||||||
events -> {
|
events -> {
|
||||||
|
@ -63,8 +62,8 @@ public class TransportGetCalendarEventsAction extends HandledTransportAction<Get
|
||||||
if (request.getJobId() != null) {
|
if (request.getJobId() != null) {
|
||||||
|
|
||||||
jobConfigProvider.getJob(request.getJobId(), ActionListener.wrap(
|
jobConfigProvider.getJob(request.getJobId(), ActionListener.wrap(
|
||||||
jobBuiler -> {
|
jobBuilder -> {
|
||||||
Job job = jobBuiler.build();
|
Job job = jobBuilder.build();
|
||||||
jobResultsProvider.scheduledEventsForJob(request.getJobId(), job.getGroups(), query, eventsListener);
|
jobResultsProvider.scheduledEventsForJob(request.getJobId(), job.getGroups(), query, eventsListener);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -74,7 +73,10 @@ public class TransportGetCalendarEventsAction extends HandledTransportAction<Get
|
||||||
groupExists -> {
|
groupExists -> {
|
||||||
if (groupExists) {
|
if (groupExists) {
|
||||||
jobResultsProvider.scheduledEventsForJob(
|
jobResultsProvider.scheduledEventsForJob(
|
||||||
null, Collections.singletonList(request.getJobId()), query, eventsListener);
|
null,
|
||||||
|
Collections.singletonList(request.getJobId()),
|
||||||
|
query,
|
||||||
|
eventsListener);
|
||||||
} else {
|
} else {
|
||||||
listener.onFailure(ExceptionsHelper.missingJobException(request.getJobId()));
|
listener.onFailure(ExceptionsHelper.missingJobException(request.getJobId()));
|
||||||
}
|
}
|
||||||
|
@ -89,16 +91,16 @@ public class TransportGetCalendarEventsAction extends HandledTransportAction<Get
|
||||||
},
|
},
|
||||||
listener::onFailure);
|
listener::onFailure);
|
||||||
|
|
||||||
checkCalendarExists(request.getCalendarId(), calendarExistsListener);
|
checkCalendarExists(calendarId, calendarExistsListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkCalendarExists(String calendarId, ActionListener<Boolean> listener) {
|
private void checkCalendarExists(String[] calendarId, ActionListener<Boolean> listener) {
|
||||||
if (Strings.isAllOrWildcard(calendarId)) {
|
if (Strings.isAllOrWildcard(calendarId)) {
|
||||||
listener.onResponse(true);
|
listener.onResponse(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
jobResultsProvider.calendar(calendarId, ActionListener.wrap(
|
jobResultsProvider.calendars(CalendarQueryBuilder.builder().calendarIdTokens(calendarId), ActionListener.wrap(
|
||||||
c -> listener.onResponse(true),
|
c -> listener.onResponse(true),
|
||||||
listener::onFailure
|
listener::onFailure
|
||||||
));
|
));
|
||||||
|
|
|
@ -14,12 +14,9 @@ import org.elasticsearch.tasks.Task;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
import org.elasticsearch.xpack.core.ml.action.GetCalendarsAction;
|
import org.elasticsearch.xpack.core.ml.action.GetCalendarsAction;
|
||||||
import org.elasticsearch.xpack.core.action.util.PageParams;
|
import org.elasticsearch.xpack.core.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.core.action.util.QueryPage;
|
|
||||||
import org.elasticsearch.xpack.core.ml.calendars.Calendar;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.CalendarQueryBuilder;
|
import org.elasticsearch.xpack.ml.job.persistence.CalendarQueryBuilder;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobResultsProvider;
|
import org.elasticsearch.xpack.ml.job.persistence.JobResultsProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
public class TransportGetCalendarsAction extends HandledTransportAction<GetCalendarsAction.Request, GetCalendarsAction.Response> {
|
public class TransportGetCalendarsAction extends HandledTransportAction<GetCalendarsAction.Request, GetCalendarsAction.Response> {
|
||||||
|
|
||||||
|
@ -34,35 +31,18 @@ public class TransportGetCalendarsAction extends HandledTransportAction<GetCalen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doExecute(Task task, GetCalendarsAction.Request request, ActionListener<GetCalendarsAction.Response> listener) {
|
protected void doExecute(Task task, GetCalendarsAction.Request request, ActionListener<GetCalendarsAction.Response> listener) {
|
||||||
final String calendarId = request.getCalendarId();
|
final String[] calendarIds = Strings.splitStringByCommaToArray(request.getCalendarId());
|
||||||
if (request.getCalendarId() != null && Strings.isAllOrWildcard(request.getCalendarId()) == false) {
|
PageParams pageParams = request.getPageParams();
|
||||||
getCalendar(calendarId, listener);
|
if (pageParams == null) {
|
||||||
} else {
|
pageParams = PageParams.defaultParams();
|
||||||
PageParams pageParams = request.getPageParams();
|
|
||||||
if (pageParams == null) {
|
|
||||||
pageParams = PageParams.defaultParams();
|
|
||||||
}
|
|
||||||
getCalendars(pageParams, listener);
|
|
||||||
}
|
}
|
||||||
|
getCalendars(calendarIds, pageParams, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getCalendar(String calendarId, ActionListener<GetCalendarsAction.Response> listener) {
|
private void getCalendars(String[] idTokens, PageParams pageParams, ActionListener<GetCalendarsAction.Response> listener) {
|
||||||
|
CalendarQueryBuilder query = new CalendarQueryBuilder().pageParams(pageParams).calendarIdTokens(idTokens).sort(true);
|
||||||
jobResultsProvider.calendar(calendarId, ActionListener.wrap(
|
|
||||||
calendar -> {
|
|
||||||
QueryPage<Calendar> page = new QueryPage<>(Collections.singletonList(calendar), 1, Calendar.RESULTS_FIELD);
|
|
||||||
listener.onResponse(new GetCalendarsAction.Response(page));
|
|
||||||
},
|
|
||||||
listener::onFailure
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getCalendars(PageParams pageParams, ActionListener<GetCalendarsAction.Response> listener) {
|
|
||||||
CalendarQueryBuilder query = new CalendarQueryBuilder().pageParams(pageParams).sort(true);
|
|
||||||
jobResultsProvider.calendars(query, ActionListener.wrap(
|
jobResultsProvider.calendars(query, ActionListener.wrap(
|
||||||
calendars -> {
|
calendars -> listener.onResponse(new GetCalendarsAction.Response(calendars)),
|
||||||
listener.onResponse(new GetCalendarsAction.Response(calendars));
|
|
||||||
},
|
|
||||||
listener::onFailure
|
listener::onFailure
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
import org.elasticsearch.action.support.HandledTransportAction;
|
||||||
|
@ -40,10 +41,17 @@ public class TransportGetModelSnapshotsAction extends HandledTransportAction<Get
|
||||||
@Override
|
@Override
|
||||||
protected void doExecute(Task task, GetModelSnapshotsAction.Request request,
|
protected void doExecute(Task task, GetModelSnapshotsAction.Request request,
|
||||||
ActionListener<GetModelSnapshotsAction.Response> listener) {
|
ActionListener<GetModelSnapshotsAction.Response> listener) {
|
||||||
logger.debug("Get model snapshots for job {} snapshot ID {}. from = {}, size = {}"
|
logger.debug(
|
||||||
+ " start = '{}', end='{}', sort={} descending={}",
|
() -> new ParameterizedMessage(
|
||||||
request.getJobId(), request.getSnapshotId(), request.getPageParams().getFrom(), request.getPageParams().getSize(),
|
"Get model snapshots for job {} snapshot ID {}. from = {}, size = {} start = '{}', end='{}', sort={} descending={}",
|
||||||
request.getStart(), request.getEnd(), request.getSort(), request.getDescOrder());
|
request.getJobId(),
|
||||||
|
request.getSnapshotId(),
|
||||||
|
request.getPageParams().getFrom(),
|
||||||
|
request.getPageParams().getSize(),
|
||||||
|
request.getStart(),
|
||||||
|
request.getEnd(),
|
||||||
|
request.getSort(),
|
||||||
|
request.getDescOrder()));
|
||||||
|
|
||||||
jobManager.jobExists(request.getJobId(), ActionListener.wrap(
|
jobManager.jobExists(request.getJobId(), ActionListener.wrap(
|
||||||
ok -> {
|
ok -> {
|
||||||
|
|
|
@ -5,13 +5,16 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.ml.job.persistence;
|
package org.elasticsearch.xpack.ml.job.persistence;
|
||||||
|
|
||||||
|
import org.elasticsearch.ResourceNotFoundException;
|
||||||
import org.elasticsearch.cluster.metadata.Metadata;
|
import org.elasticsearch.cluster.metadata.Metadata;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.index.query.TermsQueryBuilder;
|
import org.elasticsearch.index.query.TermsQueryBuilder;
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
import org.elasticsearch.xpack.core.action.util.PageParams;
|
import org.elasticsearch.xpack.core.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.core.ml.calendars.Calendar;
|
import org.elasticsearch.xpack.core.ml.calendars.Calendar;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.QueryBuilderHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -23,6 +26,11 @@ public class CalendarQueryBuilder {
|
||||||
private String jobId;
|
private String jobId;
|
||||||
private List<String> jobGroups = Collections.emptyList();
|
private List<String> jobGroups = Collections.emptyList();
|
||||||
private boolean sort = false;
|
private boolean sort = false;
|
||||||
|
private String[] idTokens = new String[0];
|
||||||
|
|
||||||
|
public static CalendarQueryBuilder builder() {
|
||||||
|
return new CalendarQueryBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page the query result
|
* Page the query result
|
||||||
|
@ -49,6 +57,19 @@ public class CalendarQueryBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CalendarQueryBuilder calendarIdTokens(String[] idTokens) {
|
||||||
|
this.idTokens = idTokens;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForAllCalendars() {
|
||||||
|
return Strings.isAllOrWildcard(idTokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Exception buildNotFoundException() {
|
||||||
|
return new ResourceNotFoundException("No calendar with id [" + Strings.arrayToCommaDelimitedString(idTokens) + "]");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort results by calendar_id
|
* Sort results by calendar_id
|
||||||
* @param sort Sort if true
|
* @param sort Sort if true
|
||||||
|
@ -60,7 +81,8 @@ public class CalendarQueryBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchSourceBuilder build() {
|
public SearchSourceBuilder build() {
|
||||||
QueryBuilder qb;
|
BoolQueryBuilder qb = QueryBuilders.boolQuery()
|
||||||
|
.filter(QueryBuilders.termQuery(Calendar.TYPE.getPreferredName(), Calendar.CALENDAR_TYPE));
|
||||||
List<String> jobIdAndGroups = new ArrayList<>(jobGroups);
|
List<String> jobIdAndGroups = new ArrayList<>(jobGroups);
|
||||||
if (jobId != null) {
|
if (jobId != null) {
|
||||||
jobIdAndGroups.add(jobId);
|
jobIdAndGroups.add(jobId);
|
||||||
|
@ -68,12 +90,11 @@ public class CalendarQueryBuilder {
|
||||||
|
|
||||||
if (jobIdAndGroups.isEmpty() == false) {
|
if (jobIdAndGroups.isEmpty() == false) {
|
||||||
jobIdAndGroups.add(Metadata.ALL);
|
jobIdAndGroups.add(Metadata.ALL);
|
||||||
qb = new BoolQueryBuilder()
|
qb.filter(new TermsQueryBuilder(Calendar.JOB_IDS.getPreferredName(), jobIdAndGroups));
|
||||||
.filter(new TermsQueryBuilder(Calendar.TYPE.getPreferredName(), Calendar.CALENDAR_TYPE))
|
|
||||||
.filter(new TermsQueryBuilder(Calendar.JOB_IDS.getPreferredName(), jobIdAndGroups));
|
|
||||||
} else {
|
|
||||||
qb = new TermsQueryBuilder(Calendar.TYPE.getPreferredName(), Calendar.CALENDAR_TYPE);
|
|
||||||
}
|
}
|
||||||
|
QueryBuilderHelper
|
||||||
|
.buildTokenFilterQuery(Calendar.ID.getPreferredName(), idTokens)
|
||||||
|
.ifPresent(qb::filter);
|
||||||
|
|
||||||
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(qb);
|
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder().query(qb);
|
||||||
|
|
||||||
|
|
|
@ -1037,12 +1037,12 @@ public class JobResultsProvider {
|
||||||
String snapshotId,
|
String snapshotId,
|
||||||
Consumer<QueryPage<ModelSnapshot>> handler,
|
Consumer<QueryPage<ModelSnapshot>> handler,
|
||||||
Consumer<Exception> errorHandler) {
|
Consumer<Exception> errorHandler) {
|
||||||
ResultsFilterBuilder fb = new ResultsFilterBuilder();
|
String[] snapshotIds = Strings.splitStringByCommaToArray(snapshotId);
|
||||||
if (snapshotId != null && !snapshotId.isEmpty()) {
|
QueryBuilder qb = new ResultsFilterBuilder()
|
||||||
fb.term(ModelSnapshotField.SNAPSHOT_ID.getPreferredName(), snapshotId);
|
.resourceTokenFilters(ModelSnapshotField.SNAPSHOT_ID.getPreferredName(), snapshotIds)
|
||||||
}
|
.timeRange(Result.TIMESTAMP.getPreferredName(), startEpochMs, endEpochMs)
|
||||||
|
.build();
|
||||||
|
|
||||||
QueryBuilder qb = fb.timeRange(Result.TIMESTAMP.getPreferredName(), startEpochMs, endEpochMs).build();
|
|
||||||
modelSnapshots(jobId, from, size, sortField, sortDescending, qb, handler, errorHandler);
|
modelSnapshots(jobId, from, size, sortField, sortDescending, qb, handler, errorHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1298,7 +1298,7 @@ public class JobResultsProvider {
|
||||||
handler.onResponse(new QueryPage<>(Collections.emptyList(), 0, ScheduledEvent.RESULTS_FIELD));
|
handler.onResponse(new QueryPage<>(Collections.emptyList(), 0, ScheduledEvent.RESULTS_FIELD));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<String> calendarIds = calendars.results().stream().map(Calendar::getId).collect(Collectors.toList());
|
String[] calendarIds = calendars.results().stream().map(Calendar::getId).toArray(String[]::new);
|
||||||
queryBuilder.calendarIds(calendarIds);
|
queryBuilder.calendarIds(calendarIds);
|
||||||
scheduledEvents(queryBuilder, handler);
|
scheduledEvents(queryBuilder, handler);
|
||||||
},
|
},
|
||||||
|
@ -1487,6 +1487,10 @@ public class JobResultsProvider {
|
||||||
List<Calendar> calendars = new ArrayList<>();
|
List<Calendar> calendars = new ArrayList<>();
|
||||||
SearchHit[] hits = response.getHits().getHits();
|
SearchHit[] hits = response.getHits().getHits();
|
||||||
try {
|
try {
|
||||||
|
if (queryBuilder.isForAllCalendars() == false && hits.length == 0) {
|
||||||
|
listener.onFailure(queryBuilder.buildNotFoundException());
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (SearchHit hit : hits) {
|
for (SearchHit hit : hits) {
|
||||||
calendars.add(MlParserUtils.parse(hit, Calendar.LENIENT_PARSER).build());
|
calendars.add(MlParserUtils.parse(hit, Calendar.LENIENT_PARSER).build());
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.index.query.RangeQueryBuilder;
|
import org.elasticsearch.index.query.RangeQueryBuilder;
|
||||||
import org.elasticsearch.index.query.TermQueryBuilder;
|
import org.elasticsearch.index.query.TermQueryBuilder;
|
||||||
import org.elasticsearch.xpack.core.ml.job.results.Result;
|
import org.elasticsearch.xpack.core.ml.job.results.Result;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.QueryBuilderHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -88,6 +89,11 @@ public class ResultsFilterBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ResultsFilterBuilder resourceTokenFilters(String fieldName, String[] tokens) {
|
||||||
|
QueryBuilderHelper.buildTokenFilterQuery(fieldName, tokens).ifPresent(this::addQuery);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ResultsFilterBuilder resultType(String resultType) {
|
public ResultsFilterBuilder resultType(String resultType) {
|
||||||
return term(Result.RESULT_TYPE.getPreferredName(), resultType);
|
return term(Result.RESULT_TYPE.getPreferredName(), resultType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,16 +6,13 @@
|
||||||
package org.elasticsearch.xpack.ml.job.persistence;
|
package org.elasticsearch.xpack.ml.job.persistence;
|
||||||
|
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.index.query.RangeQueryBuilder;
|
import org.elasticsearch.index.query.RangeQueryBuilder;
|
||||||
import org.elasticsearch.index.query.TermsQueryBuilder;
|
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
import org.elasticsearch.xpack.core.ml.calendars.Calendar;
|
import org.elasticsearch.xpack.core.ml.calendars.Calendar;
|
||||||
import org.elasticsearch.xpack.core.ml.calendars.ScheduledEvent;
|
import org.elasticsearch.xpack.core.ml.calendars.ScheduledEvent;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.QueryBuilderHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder for {@link ScheduledEvent}s
|
* Query builder for {@link ScheduledEvent}s
|
||||||
|
@ -27,11 +24,15 @@ public class ScheduledEventsQueryBuilder {
|
||||||
private Integer from = 0;
|
private Integer from = 0;
|
||||||
private Integer size = DEFAULT_SIZE;
|
private Integer size = DEFAULT_SIZE;
|
||||||
|
|
||||||
private List<String> calendarIds;
|
private String[] calendarIds;
|
||||||
private String start;
|
private String start;
|
||||||
private String end;
|
private String end;
|
||||||
|
|
||||||
public ScheduledEventsQueryBuilder calendarIds(List<String> calendarIds) {
|
public static ScheduledEventsQueryBuilder builder() {
|
||||||
|
return new ScheduledEventsQueryBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScheduledEventsQueryBuilder calendarIds(String[] calendarIds) {
|
||||||
this.calendarIds = calendarIds;
|
this.calendarIds = calendarIds;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -72,46 +73,31 @@ public class ScheduledEventsQueryBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchSourceBuilder build() {
|
public SearchSourceBuilder build() {
|
||||||
List<QueryBuilder> queries = new ArrayList<>();
|
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
|
||||||
|
.filter(QueryBuilders.termQuery(ScheduledEvent.TYPE.getPreferredName(), ScheduledEvent.SCHEDULED_EVENT_TYPE));
|
||||||
if (start != null) {
|
if (start != null) {
|
||||||
RangeQueryBuilder startQuery = QueryBuilders.rangeQuery(ScheduledEvent.END_TIME.getPreferredName());
|
RangeQueryBuilder startQuery = QueryBuilders.rangeQuery(ScheduledEvent.END_TIME.getPreferredName());
|
||||||
startQuery.gt(start);
|
startQuery.gt(start);
|
||||||
queries.add(startQuery);
|
boolQueryBuilder.filter(startQuery);
|
||||||
}
|
}
|
||||||
if (end != null) {
|
if (end != null) {
|
||||||
RangeQueryBuilder endQuery = QueryBuilders.rangeQuery(ScheduledEvent.START_TIME.getPreferredName());
|
RangeQueryBuilder endQuery = QueryBuilders.rangeQuery(ScheduledEvent.START_TIME.getPreferredName());
|
||||||
endQuery.lt(end);
|
endQuery.lt(end);
|
||||||
queries.add(endQuery);
|
boolQueryBuilder.filter(endQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calendarIds != null && calendarIds.isEmpty() == false) {
|
QueryBuilderHelper.buildTokenFilterQuery(Calendar.ID.getPreferredName(), calendarIds).ifPresent(boolQueryBuilder::filter);
|
||||||
queries.add(new TermsQueryBuilder(Calendar.ID.getPreferredName(), calendarIds));
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryBuilder typeQuery = new TermsQueryBuilder(ScheduledEvent.TYPE.getPreferredName(), ScheduledEvent.SCHEDULED_EVENT_TYPE);
|
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource()
|
||||||
|
.sort(ScheduledEvent.START_TIME.getPreferredName())
|
||||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
.sort(ScheduledEvent.DESCRIPTION.getPreferredName())
|
||||||
searchSourceBuilder.sort(ScheduledEvent.START_TIME.getPreferredName());
|
.query(boolQueryBuilder);
|
||||||
searchSourceBuilder.sort(ScheduledEvent.DESCRIPTION.getPreferredName());
|
|
||||||
if (from != null) {
|
if (from != null) {
|
||||||
searchSourceBuilder.from(from);
|
searchSourceBuilder.from(from);
|
||||||
}
|
}
|
||||||
if (size != null) {
|
if (size != null) {
|
||||||
searchSourceBuilder.size(size);
|
searchSourceBuilder.size(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queries.isEmpty()) {
|
|
||||||
searchSourceBuilder.query(typeQuery);
|
|
||||||
} else {
|
|
||||||
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
|
|
||||||
boolQueryBuilder.filter(typeQuery);
|
|
||||||
for (QueryBuilder query : queries) {
|
|
||||||
boolQueryBuilder.filter(query);
|
|
||||||
}
|
|
||||||
searchSourceBuilder.query(boolQueryBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
return searchSourceBuilder;
|
return searchSourceBuilder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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.utils;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.regex.Regex;
|
||||||
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.TermsQueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.WildcardQueryBuilder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class QueryBuilderHelper {
|
||||||
|
|
||||||
|
private QueryBuilderHelper() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for adding OR type queries for a given identity field.
|
||||||
|
*
|
||||||
|
* The filter consists of should clauses (i.e. "or" boolean queries).
|
||||||
|
*
|
||||||
|
* - When a token is a wildcard token, a wildcard query is added
|
||||||
|
* - When a token is NOT a wildcard, a term query is added
|
||||||
|
*
|
||||||
|
* @param identityField The field to query for the tokens
|
||||||
|
* @param tokens A non-null collection of tokens. Can include wildcards
|
||||||
|
* @return An optional boolean query builder filled with "should" queries for the supplied tokens and identify field
|
||||||
|
*/
|
||||||
|
public static Optional<QueryBuilder> buildTokenFilterQuery(String identityField, String[] tokens) {
|
||||||
|
if (Strings.isAllOrWildcard(tokens)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolQueryBuilder shouldQueries = new BoolQueryBuilder();
|
||||||
|
List<String> terms = new ArrayList<>();
|
||||||
|
for (String token : tokens) {
|
||||||
|
if (Regex.isSimpleMatchPattern(token)) {
|
||||||
|
shouldQueries.should(new WildcardQueryBuilder(identityField, token));
|
||||||
|
} else {
|
||||||
|
terms.add(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terms.isEmpty() == false) {
|
||||||
|
shouldQueries.should(new TermsQueryBuilder(identityField, terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldQueries.should().isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.of(shouldQueries);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
---
|
---
|
||||||
"Test calendar CRUD":
|
"Test calendar CRUD":
|
||||||
|
- do:
|
||||||
|
ml.get_calendars:
|
||||||
|
calendar_id: _all
|
||||||
|
- match: { count: 0 }
|
||||||
|
|
||||||
- do:
|
- do:
|
||||||
ml.put_job:
|
ml.put_job:
|
||||||
|
|
Loading…
Reference in New Issue