added support for template params in search requests

Original commit: elastic/x-pack-elasticsearch@06e7dab935
This commit is contained in:
uboness 2015-03-03 12:01:45 +02:00
parent f9765fd393
commit dfc8249d4b
5 changed files with 147 additions and 104 deletions

View File

@ -130,9 +130,8 @@ public class SearchInput extends Input<SearchInput.Result> {
request.templateParams(templateParams.map()); request.templateParams(templateParams.map());
request.templateName(requestPrototype.templateName()); request.templateName(requestPrototype.templateName());
request.templateType(requestPrototype.templateType()); request.templateType(requestPrototype.templateType());
} else {
throw new InputException("search requests needs either source or template name");
} }
// falling back to an empty body
return request; return request;
} }

View File

@ -11,7 +11,10 @@ import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.alerts.AlertsException; import org.elasticsearch.alerts.AlertsException;
import org.elasticsearch.alerts.AlertsSettingsException;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentHelper;
@ -19,11 +22,10 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.lang.reflect.Array;
import java.util.List; import java.util.*;
import java.util.Locale;
import java.util.Map;
import static org.elasticsearch.alerts.support.AlertsDateUtils.formatDate;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
/** /**
@ -50,14 +52,13 @@ public final class AlertUtils {
public static SearchRequest readSearchRequest(XContentParser parser, SearchType searchType) throws IOException { public static SearchRequest readSearchRequest(XContentParser parser, SearchType searchType) throws IOException {
SearchRequest searchRequest = new SearchRequest(); SearchRequest searchRequest = new SearchRequest();
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS; IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
XContentParser.Token token; XContentParser.Token token;
String searchRequestFieldName = null; String currentFieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
searchRequestFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_ARRAY) { } else if (token == XContentParser.Token.START_ARRAY) {
switch (searchRequestFieldName) { switch (currentFieldName) {
case "indices": case "indices":
List<String> indices = new ArrayList<>(); List<String> indices = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
@ -70,11 +71,11 @@ public final class AlertUtils {
searchRequest.indices(indices.toArray(new String[indices.size()])); searchRequest.indices(indices.toArray(new String[indices.size()]));
break; break;
default: default:
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]"); throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
} }
} else if (token == XContentParser.Token.START_OBJECT) { } else if (token == XContentParser.Token.START_OBJECT) {
XContentBuilder builder; XContentBuilder builder;
switch (searchRequestFieldName) { switch (currentFieldName) {
case "body": case "body":
builder = XContentBuilder.builder(parser.contentType().xContent()); builder = XContentBuilder.builder(parser.contentType().xContent());
builder.copyCurrentStructure(parser); builder.copyCurrentStructure(parser);
@ -125,25 +126,43 @@ public final class AlertUtils {
} }
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed); indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed);
break; break;
default: case "template":
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]"); while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
} if (token == XContentParser.Token.FIELD_NAME) {
} else if (token.isValue()) { currentFieldName = parser.currentName();
switch (searchRequestFieldName) { } else if (token == XContentParser.Token.VALUE_STRING) {
case "template_name": switch (currentFieldName) {
case "name":
searchRequest.templateName(parser.textOrNull()); searchRequest.templateName(parser.textOrNull());
break; break;
case "template_type": case "type":
try {
searchRequest.templateType(ScriptService.ScriptType.valueOf(parser.text().toUpperCase(Locale.ROOT))); searchRequest.templateType(ScriptService.ScriptType.valueOf(parser.text().toUpperCase(Locale.ROOT)));
} catch (IllegalArgumentException iae) {
throw new AlertsSettingsException("could not parse search request. unknown template type [" + parser.text() + "]");
}
}
} else if (token == XContentParser.Token.START_OBJECT) {
if ("params".equals(currentFieldName)) {
searchRequest.templateParams(flattenModel(parser.map()));
}
}
}
break; break;
default:
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
}
} else if (token.isValue()) {
switch (currentFieldName) {
case "search_type": case "search_type":
searchType = SearchType.fromString(parser.text().toLowerCase(Locale.ROOT)); searchType = SearchType.fromString(parser.text().toLowerCase(Locale.ROOT));
break; break;
default: default:
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]"); throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
} }
} else { } else {
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]"); throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
} }
} }
@ -172,11 +191,17 @@ public final class AlertUtils {
XContentHelper.writeRawField("body", searchRequest.source(), builder, params); XContentHelper.writeRawField("body", searchRequest.source(), builder, params);
} }
if (searchRequest.templateName() != null) { if (searchRequest.templateName() != null) {
builder.field("template_name", searchRequest.templateName()); builder.startObject("template")
} .field("name", searchRequest.templateName());
if (searchRequest.templateType() != null) { if (searchRequest.templateType() != null) {
builder.field("template_type", searchRequest.templateType().name().toLowerCase(Locale.ROOT)); builder.field("type", searchRequest.templateType().name().toLowerCase(Locale.ROOT));
} }
if (searchRequest.templateParams() != null && !searchRequest.templateParams().isEmpty()) {
builder.field("params", searchRequest.templateParams());
}
builder.endObject();
}
if (searchRequest.indicesOptions() != DEFAULT_INDICES_OPTIONS) { if (searchRequest.indicesOptions() != DEFAULT_INDICES_OPTIONS) {
IndicesOptions options = searchRequest.indicesOptions(); IndicesOptions options = searchRequest.indicesOptions();
builder.startObject("indices_options"); builder.startObject("indices_options");
@ -198,4 +223,44 @@ public final class AlertUtils {
return builder.endObject(); return builder.endObject();
} }
public static Map<String, String> flattenModel(Map<String, Object> map) {
Map<String, String> result = new HashMap<>();
flattenModel("", map, result);
return result;
}
private static void flattenModel(String key, Object value, Map<String, String> result) {
if (value instanceof Map) {
for (Map.Entry<String, Object> entry : ((Map<String, Object>) value).entrySet()) {
if ("".equals(key)) {
flattenModel(entry.getKey(), entry.getValue(), result);
} else {
flattenModel(key + "." + entry.getKey(), entry.getValue(), result);
}
}
return;
}
if (value instanceof Iterable) {
int i = 0;
for (Object item : (Iterable) value) {
flattenModel(key + "." + i++, item, result);
}
return;
}
if (value.getClass().isArray()) {
for (int i = 0; i < Array.getLength(value); i++) {
flattenModel(key + "." + i, Array.get(value, i), result);
}
return;
}
if (value instanceof DateTime) {
result.put(key, formatDate((DateTime) value));
return;
}
if (value instanceof TimeValue) {
result.put(key, String.valueOf(((TimeValue) value).getMillis()));
return;
}
result.put(key, String.valueOf(value));
}
} }

View File

@ -18,10 +18,8 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentHelper;
@ -30,11 +28,8 @@ import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.alerts.support.AlertsDateUtils.formatDate; import static org.elasticsearch.alerts.support.AlertUtils.flattenModel;
import static org.elasticsearch.alerts.support.Variables.createCtxModel; import static org.elasticsearch.alerts.support.Variables.createCtxModel;
/** /**
@ -86,7 +81,7 @@ public class SearchTransform extends Transform {
request.source((BytesReference) script.unwrap(script.run()), false); request.source((BytesReference) script.unwrap(script.run()), false);
} else if (requestPrototype.templateName() != null) { } else if (requestPrototype.templateName() != null) {
MapBuilder<String, String> templateParams = MapBuilder.newMapBuilder(requestPrototype.templateParams()) MapBuilder<String, String> templateParams = MapBuilder.newMapBuilder(requestPrototype.templateParams())
.putAll(flatten(createCtxModel(ctx, payload))); .putAll(flattenModel(createCtxModel(ctx, payload)));
request.templateParams(templateParams.map()); request.templateParams(templateParams.map());
request.templateName(requestPrototype.templateName()); request.templateName(requestPrototype.templateName());
request.templateType(requestPrototype.templateType()); request.templateType(requestPrototype.templateType());
@ -96,47 +91,6 @@ public class SearchTransform extends Transform {
return request; return request;
} }
static Map<String, String> flatten(Map<String, Object> map) {
Map<String, String> result = new HashMap<>();
flatten("", map, result);
return result;
}
private static void flatten(String key, Object value, Map<String, String> result) {
if (value instanceof Map) {
for (Map.Entry<String, Object> entry : ((Map<String, Object>) value).entrySet()) {
if ("".equals(key)) {
flatten(entry.getKey(), entry.getValue(), result);
} else {
flatten(key + "." + entry.getKey(), entry.getValue(), result);
}
}
return;
}
if (value instanceof Iterable) {
int i = 0;
for (Object item : (Iterable) value) {
flatten(key + "." + i++, item, result);
}
return;
}
if (value.getClass().isArray()) {
for (int i = 0; i < Array.getLength(value); i++) {
flatten(key + "." + i, Array.get(value, i), result);
}
return;
}
if (value instanceof DateTime) {
result.put(key, formatDate((DateTime) value));
return;
}
if (value instanceof TimeValue) {
result.put(key, String.valueOf(((TimeValue) value).getMillis()));
return;
}
result.put(key, String.valueOf(value));
}
public static class Parser extends AbstractComponent implements Transform.Parser<SearchTransform> { public static class Parser extends AbstractComponent implements Transform.Parser<SearchTransform> {
protected final ScriptServiceProxy scriptService; protected final ScriptServiceProxy scriptService;

View File

@ -0,0 +1,49 @@
/*
* 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.alerts.support;
import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.unit.TimeValue;
import org.junit.Test;
import java.util.Map;
import static org.elasticsearch.alerts.support.AlertUtils.flattenModel;
import static org.elasticsearch.alerts.support.AlertsDateUtils.formatDate;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
/**
*
*/
public class AlertUtilsTests {
@Test
public void testFlattenModel() throws Exception {
DateTime now = new DateTime();
Map<String, Object> map = ImmutableMap.<String, Object>builder()
.put("a", ImmutableMap.builder().put("a1", new int[] { 0, 1, 2 }).build())
.put("b", new String[] { "b0", "b1", "b2" })
.put("c", ImmutableList.of(TimeValue.timeValueSeconds(0), TimeValue.timeValueSeconds(1)))
.put("d", now)
.build();
Map<String, String> result = flattenModel(map);
assertThat(result.size(), is(9));
assertThat(result, hasEntry("a.a1.0", "0"));
assertThat(result, hasEntry("a.a1.1", "1"));
assertThat(result, hasEntry("a.a1.2", "2"));
assertThat(result, hasEntry("b.0", "b0"));
assertThat(result, hasEntry("b.1", "b1"));
assertThat(result, hasEntry("b.2", "b2"));
assertThat(result, hasEntry("c.0", "0"));
assertThat(result, hasEntry("c.1", "1000"));
assertThat(result, hasEntry("d", formatDate(now)));
}
}

View File

@ -16,11 +16,9 @@ import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
import org.elasticsearch.alerts.test.AbstractAlertsSingleNodeTests; import org.elasticsearch.alerts.test.AbstractAlertsSingleNodeTests;
import org.elasticsearch.client.Requests; import org.elasticsearch.client.Requests;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
@ -30,7 +28,6 @@ import org.junit.Test;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.alerts.support.AlertsDateUtils.formatDate;
import static org.elasticsearch.alerts.support.AlertsDateUtils.parseDate; import static org.elasticsearch.alerts.support.AlertsDateUtils.parseDate;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.FilterBuilders.*; import static org.elasticsearch.index.query.FilterBuilders.*;
@ -172,10 +169,12 @@ public class SearchTransformTests extends AbstractAlertsSingleNodeTests {
builder.field("search_type", searchType.name()); builder.field("search_type", searchType.name());
} }
if (templateName != null) { if (templateName != null) {
builder.field("template_name", templateName); builder.startObject("template")
} .field("name", templateName);
if (templateType != null) { if (templateType != null) {
builder.field("template_type", templateType); builder.field("type", templateType);
}
builder.endObject();
} }
XContentBuilder sourceBuilder = jsonBuilder().startObject() XContentBuilder sourceBuilder = jsonBuilder().startObject()
@ -215,29 +214,6 @@ public class SearchTransformTests extends AbstractAlertsSingleNodeTests {
assertThat(transform.request.source().toBytes(), equalTo(source.toBytes())); assertThat(transform.request.source().toBytes(), equalTo(source.toBytes()));
} }
@Test
public void testFlatten() throws Exception {
DateTime now = new DateTime();
Map<String, Object> map = ImmutableMap.<String, Object>builder()
.put("a", ImmutableMap.builder().put("a1", new int[] { 0, 1, 2 }).build())
.put("b", new String[] { "b0", "b1", "b2" })
.put("c", ImmutableList.of( TimeValue.timeValueSeconds(0), TimeValue.timeValueSeconds(1)))
.put("d", now)
.build();
Map<String, String> result = SearchTransform.flatten(map);
assertThat(result.size(), is(9));
assertThat(result, hasEntry("a.a1.0", "0"));
assertThat(result, hasEntry("a.a1.1", "1"));
assertThat(result, hasEntry("a.a1.2", "2"));
assertThat(result, hasEntry("b.0", "b0"));
assertThat(result, hasEntry("b.1", "b1"));
assertThat(result, hasEntry("b.2", "b2"));
assertThat(result, hasEntry("c.0", "0"));
assertThat(result, hasEntry("c.1", "1000"));
assertThat(result, hasEntry("d", formatDate(now)));
}
private static Map<String, Object> doc(String date, String value) { private static Map<String, Object> doc(String date, String value) {
Map<String, Object> doc = new HashMap<>(); Map<String, Object> doc = new HashMap<>();
doc.put("date", parseDate(date)); doc.put("date", parseDate(date));