Added `search_type` option to the trigger search in an alert.
The default `search_type` is `count`. Closes elastic/elasticsearch#38 Original commit: elastic/x-pack-elasticsearch@8e87aaea36
This commit is contained in:
parent
732d7018b4
commit
43043ce3ce
|
@ -7,6 +7,7 @@ package org.elasticsearch.alerts;
|
|||
|
||||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
|
@ -18,11 +19,15 @@ import org.elasticsearch.script.ScriptService;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
*/
|
||||
public final class AlertUtils {
|
||||
|
||||
public final static IndicesOptions DEFAULT_INDICES_OPTIONS = IndicesOptions.lenientExpandOpen();
|
||||
public final static SearchType DEFAULT_SEARCH_TYPE = SearchType.COUNT;
|
||||
|
||||
private AlertUtils() {
|
||||
}
|
||||
|
||||
|
@ -30,10 +35,12 @@ public final class AlertUtils {
|
|||
* Reads a new search request instance for the specified parser.
|
||||
*/
|
||||
public static SearchRequest readSearchRequest(XContentParser parser) throws IOException {
|
||||
String searchRequestFieldName = null;
|
||||
XContentParser.Token token;
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
searchRequest.indicesOptions(IndicesOptions.lenientExpandOpen()); // TODO: make options configurable
|
||||
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
|
||||
SearchType searchType = DEFAULT_SEARCH_TYPE;
|
||||
|
||||
XContentParser.Token token;
|
||||
String searchRequestFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
searchRequestFieldName = parser.currentName();
|
||||
|
@ -61,6 +68,51 @@ public final class AlertUtils {
|
|||
builder.copyCurrentStructure(parser);
|
||||
searchRequest.source(builder);
|
||||
break;
|
||||
case "indices_options":
|
||||
boolean expandOpen = indicesOptions.expandWildcardsOpen();
|
||||
boolean expandClosed = indicesOptions.expandWildcardsClosed();
|
||||
boolean allowNoIndices = indicesOptions.allowNoIndices();
|
||||
boolean ignoreUnavailable = indicesOptions.ignoreUnavailable();
|
||||
|
||||
String indicesFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
indicesFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
switch (indicesFieldName) {
|
||||
case "expand_wildcards":
|
||||
switch (parser.text()) {
|
||||
case "all":
|
||||
expandOpen = true;
|
||||
expandClosed = true;
|
||||
break;
|
||||
case "open":
|
||||
expandOpen = true;
|
||||
break;
|
||||
case "closed":
|
||||
expandClosed = true;
|
||||
break;
|
||||
case "none":
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected value [" + parser.text() + "]");
|
||||
}
|
||||
break;
|
||||
case "ignore_unavailable":
|
||||
ignoreUnavailable = parser.booleanValue();
|
||||
break;
|
||||
case "allow_no_indices":
|
||||
allowNoIndices = parser.booleanValue();
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + indicesFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected token [" + token + "]");
|
||||
}
|
||||
}
|
||||
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed);
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]");
|
||||
}
|
||||
|
@ -72,6 +124,9 @@ public final class AlertUtils {
|
|||
case "template_type":
|
||||
searchRequest.templateType(readScriptType(parser.textOrNull()));
|
||||
break;
|
||||
case "search_type":
|
||||
searchType = SearchType.fromString(parser.text());
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]");
|
||||
}
|
||||
|
@ -79,6 +134,9 @@ public final class AlertUtils {
|
|||
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
searchRequest.searchType(searchType);
|
||||
searchRequest.indicesOptions(indicesOptions);
|
||||
return searchRequest;
|
||||
}
|
||||
|
||||
|
@ -101,6 +159,27 @@ public final class AlertUtils {
|
|||
builder.value(index);
|
||||
}
|
||||
builder.endArray();
|
||||
if (searchRequest.indicesOptions() != DEFAULT_INDICES_OPTIONS) {
|
||||
IndicesOptions options = searchRequest.indicesOptions();
|
||||
builder.startObject("indices_options");
|
||||
String value;
|
||||
if (options.expandWildcardsClosed() && options.expandWildcardsOpen()) {
|
||||
value = "all";
|
||||
} else if (options.expandWildcardsOpen()) {
|
||||
value = "open";
|
||||
} else if (options.expandWildcardsClosed()) {
|
||||
value = "closed";
|
||||
} else {
|
||||
value = "none";
|
||||
}
|
||||
builder.field("expand_wildcards", value);
|
||||
builder.field("ignore_unavailable", options.ignoreUnavailable());
|
||||
builder.field("allow_no_indices", options.allowNoIndices());
|
||||
builder.endObject();
|
||||
}
|
||||
if (searchRequest.searchType() != DEFAULT_SEARCH_TYPE) {
|
||||
builder.field("search_type", searchRequest.searchType().toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
|
|
|
@ -95,6 +95,13 @@ public abstract class AbstractAlertingTests extends ElasticsearchIntegrationTest
|
|||
return builder.endObject().bytes();
|
||||
}
|
||||
|
||||
protected SearchRequest createTriggerSearchRequest(String... indices) {
|
||||
SearchRequest request = new SearchRequest(indices);
|
||||
request.indicesOptions(AlertUtils.DEFAULT_INDICES_OPTIONS);
|
||||
request.searchType(AlertUtils.DEFAULT_SEARCH_TYPE);
|
||||
return request;
|
||||
}
|
||||
|
||||
protected AlertsClient alertClient() {
|
||||
return internalTestCluster().getInstance(AlertsClient.class);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.alerts;
|
|||
|
||||
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.alerts.client.AlertsClient;
|
||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertRequest;
|
||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertResponse;
|
||||
|
@ -36,7 +37,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
createIndex("my-index");
|
||||
// Have a sample document in the index, the alert is going to evaluate
|
||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
||||
SearchRequest searchRequest = new SearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = createTriggerSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
alertsClient.prepareIndexAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
|
@ -47,7 +48,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
@Test
|
||||
public void testIndexAlert_registerAlertBeforeTargetIndex() throws Exception {
|
||||
AlertsClient alertsClient = alertClient();
|
||||
SearchRequest searchRequest = new SearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = createTriggerSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
alertsClient.prepareIndexAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
|
@ -67,7 +68,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
createIndex("my-index");
|
||||
// Have a sample document in the index, the alert is going to evaluate
|
||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
||||
SearchRequest searchRequest = new SearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest searchRequest = createTriggerSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
PutAlertResponse indexResponse = alertsClient.prepareIndexAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
|
@ -119,6 +120,23 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlertWithDifferentSearchType() throws Exception {
|
||||
AlertsClient alertsClient = alertClient();
|
||||
createIndex("my-index");
|
||||
// Have a sample document in the index, the alert is going to evaluate
|
||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
||||
SearchRequest searchRequest = createTriggerSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
searchRequest.searchType(SearchType.QUERY_THEN_FETCH);
|
||||
// By accessing the actual hit we know that the fetch phase has been performed
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits?.hits[0]._score == 1.0");
|
||||
PutAlertResponse indexResponse = alertsClient.prepareIndexAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
.get();
|
||||
assertThat(indexResponse.indexResponse().isCreated(), is(true));
|
||||
assertAlertTriggered("my-first-alert", 1);
|
||||
}
|
||||
|
||||
private final SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
||||
filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{SCHEDULED_FIRE_TIME}}||-30s").to("{{SCHEDULED_FIRE_TIME}}"))
|
||||
);
|
||||
|
@ -126,7 +144,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
@Test
|
||||
public void testTriggerSearchWithSource() throws Exception {
|
||||
testTriggerSearch(
|
||||
new SearchRequest("my-index").source(searchSourceBuilder)
|
||||
createTriggerSearchRequest("my-index").source(searchSourceBuilder)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -137,7 +155,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
.setId("my-template")
|
||||
.setSource(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject())
|
||||
.get();
|
||||
SearchRequest searchRequest = new SearchRequest("my-index");
|
||||
SearchRequest searchRequest = createTriggerSearchRequest("my-index");
|
||||
searchRequest.templateName("my-template");
|
||||
searchRequest.templateType(ScriptService.ScriptType.INDEXED);
|
||||
testTriggerSearch(searchRequest);
|
||||
|
|
Loading…
Reference in New Issue