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.templateName(requestPrototype.templateName());
request.templateType(requestPrototype.templateType());
} else {
throw new InputException("search requests needs either source or template name");
}
// falling back to an empty body
return request;
}

View File

@ -11,7 +11,10 @@ import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.alerts.AlertsException;
import org.elasticsearch.alerts.AlertsSettingsException;
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.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
@ -19,11 +22,10 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.lang.reflect.Array;
import java.util.*;
import static org.elasticsearch.alerts.support.AlertsDateUtils.formatDate;
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 {
SearchRequest searchRequest = new SearchRequest();
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
XContentParser.Token token;
String searchRequestFieldName = null;
String currentFieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
searchRequestFieldName = parser.currentName();
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.START_ARRAY) {
switch (searchRequestFieldName) {
switch (currentFieldName) {
case "indices":
List<String> indices = new ArrayList<>();
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
@ -70,11 +71,11 @@ public final class AlertUtils {
searchRequest.indices(indices.toArray(new String[indices.size()]));
break;
default:
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]");
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.START_OBJECT) {
XContentBuilder builder;
switch (searchRequestFieldName) {
switch (currentFieldName) {
case "body":
builder = XContentBuilder.builder(parser.contentType().xContent());
builder.copyCurrentStructure(parser);
@ -125,25 +126,43 @@ public final class AlertUtils {
}
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed);
break;
case "template":
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (token == XContentParser.Token.VALUE_STRING) {
switch (currentFieldName) {
case "name":
searchRequest.templateName(parser.textOrNull());
break;
case "type":
try {
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;
default:
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]");
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
}
} else if (token.isValue()) {
switch (searchRequestFieldName) {
case "template_name":
searchRequest.templateName(parser.textOrNull());
break;
case "template_type":
searchRequest.templateType(ScriptService.ScriptType.valueOf(parser.text().toUpperCase(Locale.ROOT)));
break;
switch (currentFieldName) {
case "search_type":
searchType = SearchType.fromString(parser.text().toLowerCase(Locale.ROOT));
break;
default:
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + searchRequestFieldName + "]");
throw new ElasticsearchIllegalArgumentException("Unexpected field [" + currentFieldName + "]");
}
} 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);
}
if (searchRequest.templateName() != null) {
builder.field("template_name", searchRequest.templateName());
}
if (searchRequest.templateType() != null) {
builder.field("template_type", searchRequest.templateType().name().toLowerCase(Locale.ROOT));
builder.startObject("template")
.field("name", searchRequest.templateName());
if (searchRequest.templateType() != null) {
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) {
IndicesOptions options = searchRequest.indicesOptions();
builder.startObject("indices_options");
@ -198,4 +223,44 @@ public final class AlertUtils {
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.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
@ -30,11 +28,8 @@ import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
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;
/**
@ -86,7 +81,7 @@ public class SearchTransform extends Transform {
request.source((BytesReference) script.unwrap(script.run()), false);
} else if (requestPrototype.templateName() != null) {
MapBuilder<String, String> templateParams = MapBuilder.newMapBuilder(requestPrototype.templateParams())
.putAll(flatten(createCtxModel(ctx, payload)));
.putAll(flattenModel(createCtxModel(ctx, payload)));
request.templateParams(templateParams.map());
request.templateName(requestPrototype.templateName());
request.templateType(requestPrototype.templateType());
@ -96,47 +91,6 @@ public class SearchTransform extends Transform {
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> {
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.client.Requests;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
@ -30,7 +28,6 @@ import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.alerts.support.AlertsDateUtils.formatDate;
import static org.elasticsearch.alerts.support.AlertsDateUtils.parseDate;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.FilterBuilders.*;
@ -172,10 +169,12 @@ public class SearchTransformTests extends AbstractAlertsSingleNodeTests {
builder.field("search_type", searchType.name());
}
if (templateName != null) {
builder.field("template_name", templateName);
}
if (templateType != null) {
builder.field("template_type", templateType);
builder.startObject("template")
.field("name", templateName);
if (templateType != null) {
builder.field("type", templateType);
}
builder.endObject();
}
XContentBuilder sourceBuilder = jsonBuilder().startObject()
@ -215,29 +214,6 @@ public class SearchTransformTests extends AbstractAlertsSingleNodeTests {
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) {
Map<String, Object> doc = new HashMap<>();
doc.put("date", parseDate(date));