Removed deprecated template query.

Relates to #19390
This commit is contained in:
Martijn van Groningen 2017-05-10 12:18:19 +02:00
parent e49ebd04fd
commit 840da4aebf
No known key found for this signature in database
GPG Key ID: AB236F4FCF2AF12A
9 changed files with 4 additions and 630 deletions

View File

@ -51,6 +51,8 @@
* The `disable_coord` parameter of the `bool` and `common_terms` queries has
been removed. If provided, it will be ignored and issue a deprecation warning.
* The `template` query has been removed. This query was deprecated since 5.0
==== Search shards API
The search shards API no longer accepts the `type` url parameter, which didn't

View File

@ -9,12 +9,6 @@ This group contains queries which do not fit into the other groups:
This query finds documents which are similar to the specified text, document,
or collection of documents.
<<query-dsl-template-query,`template` query>>::
The `template` query accepts a Mustache template (either inline, indexed, or
from a file), and a map of parameters, and combines the two to generate the
final query to execute.
<<query-dsl-script-query,`script` query>>::
This query allows a script to act as a filter. Also see the
@ -27,8 +21,6 @@ the specified document.
include::mlt-query.asciidoc[]
include::template-query.asciidoc[]
include::script-query.asciidoc[]
include::percolate-query.asciidoc[]

View File

@ -1,127 +0,0 @@
[[query-dsl-template-query]]
=== Template Query
deprecated[5.0.0, Use the <<search-template>> API]
A query that accepts a query template and a map of key/value pairs to fill in
template parameters. Templating is based on Mustache. For simple token substitution all you provide
is a query containing some variable that you want to substitute and the actual
values:
[source,js]
------------------------------------------
GET /_search
{
"query": {
"template": {
"inline": { "match": { "text": "{{query_string}}" }},
"params" : {
"query_string" : "all about search"
}
}
}
}
------------------------------------------
// CONSOLE
// TEST[warning:[template] query is deprecated, use search template api instead]
The above request is translated into:
[source,js]
------------------------------------------
GET /_search
{
"query": {
"match": {
"text": "all about search"
}
}
}
------------------------------------------
// CONSOLE
Alternatively passing the template as an escaped string works as well:
[source,js]
------------------------------------------
GET /_search
{
"query": {
"template": {
"inline": "{ \"match\": { \"text\": \"{{query_string}}\" }}", <1>
"params" : {
"query_string" : "all about search"
}
}
}
}
------------------------------------------
// CONSOLE
// TEST[warning:[template] query is deprecated, use search template api instead]
<1> New line characters (`\n`) should be escaped as `\\n` or removed,
and quotes (`"`) should be escaped as `\\"`.
==== Stored templates
You can register a template by storing it in the `config/scripts` directory, in a file using the `.mustache` extension.
In order to execute the stored template, reference it by name in the `file`
parameter:
[source,js]
------------------------------------------
GET /_search
{
"query": {
"template": {
"file": "my_template", <1>
"params" : {
"query_string" : "all about search"
}
}
}
}
------------------------------------------
// CONSOLE
// TEST[warning:[template] query is deprecated, use search template api instead]
<1> Name of the query template in `config/scripts/`, i.e., `my_template.mustache`.
Alternatively, you can register a query template in the cluster state with:
[source,js]
------------------------------------------
PUT /_search/template/my_template
{
"template": { "match": { "text": "{{query_string}}" }}
}
------------------------------------------
// CONSOLE
and refer to it in the `template` query with the `id` parameter:
[source,js]
------------------------------------------
GET /_search
{
"query": {
"template": {
"stored": "my_template", <1>
"params" : {
"query_string" : "all about search"
}
}
}
}
------------------------------------------
// CONSOLE
// TEST[continued]
// TEST[warning:[template] query is deprecated, use search template api instead]
<1> Name of the query template in `config/scripts/`, i.e., `my_template.mustache`.
There is also a dedicated `template` endpoint, allows you to template an entire search request.
Please see <<search-template>> for more details.

View File

@ -213,8 +213,8 @@ The response contains suggestions scored by the most likely spell correction fir
Checks each suggestion against the specified `query` to prune suggestions
for which no matching docs exist in the index. The collate query for a
suggestion is run only on the local shard from which the suggestion has
been generated from. The `query` must be specified, and it is run as
a <<query-dsl-template-query,`template` query>>.
been generated from. The `query` must be specified and it can be templated,
see <<search-template,search templates>> for more information.
The current suggestion is automatically made available as the `{{suggestion}}`
variable, which should be used in your query. You can still specify
your own template `params` -- the `suggestion` value will be added to the

View File

@ -39,8 +39,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import static java.util.Collections.singletonList;
public class MustachePlugin extends Plugin implements ScriptPlugin, ActionPlugin, SearchPlugin {
@Override
@ -54,11 +52,6 @@ public class MustachePlugin extends Plugin implements ScriptPlugin, ActionPlugin
new ActionHandler<>(MultiSearchTemplateAction.INSTANCE, TransportMultiSearchTemplateAction.class));
}
@Override
public List<QuerySpec<?>> getQueries() {
return singletonList(new QuerySpec<>(TemplateQueryBuilder.NAME, TemplateQueryBuilder::new, TemplateQueryBuilder::fromXContent));
}
@Override
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver,

View File

@ -1,151 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.script.mustache;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryRewriteContext;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
/**
* Facilitates creating template query requests.
* */
@Deprecated
// TODO remove this class in 6.0
public class TemplateQueryBuilder extends AbstractQueryBuilder<TemplateQueryBuilder> {
public static final String NAME = "template";
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(Loggers.getLogger(TemplateQueryBuilder.class));
/** Template to fill. */
private final Script template;
public TemplateQueryBuilder(String template, ScriptType scriptType, Map<String, Object> params) {
this(new Script(scriptType, "mustache", template, params));
}
public TemplateQueryBuilder(String template, ScriptType scriptType, Map<String, Object> params, XContentType ct) {
this(new Script(scriptType, "mustache", template, scriptType == ScriptType.INLINE ?
(ct == null ? Collections.emptyMap() : Collections.singletonMap(Script.CONTENT_TYPE_OPTION, ct.mediaType()))
: null, params));
}
TemplateQueryBuilder(Script template) {
DEPRECATION_LOGGER.deprecated("[{}] query is deprecated, use search template api instead", NAME);
if (template == null) {
throw new IllegalArgumentException("query template cannot be null");
}
this.template = template;
}
public Script template() {
return template;
}
/**
* Read from a stream.
*/
public TemplateQueryBuilder(StreamInput in) throws IOException {
super(in);
template = new Script(in);
}
@Override
protected void doWriteTo(StreamOutput out) throws IOException {
template.writeTo(out);
}
@Override
protected void doXContent(XContentBuilder builder, Params builderParams) throws IOException {
builder.field(TemplateQueryBuilder.NAME);
template.toXContent(builder, builderParams);
}
@Override
public String getWriteableName() {
return NAME;
}
@Override
protected Query doToQuery(QueryShardContext context) throws IOException {
throw new UnsupportedOperationException("this query must be rewritten first");
}
@Override
protected int doHashCode() {
return Objects.hash(template);
}
@Override
protected boolean doEquals(TemplateQueryBuilder other) {
return Objects.equals(template, other.template);
}
@Override
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
BytesReference querySource = queryRewriteContext.getTemplateBytes(template);
try (XContentParser qSourceParser = XContentFactory.xContent(querySource).createParser(queryRewriteContext.getXContentRegistry(),
querySource)) {
final QueryParseContext queryParseContext = queryRewriteContext.newParseContext(qSourceParser);
final QueryBuilder queryBuilder = queryParseContext.parseInnerQueryBuilder();
if (boost() != DEFAULT_BOOST || queryName() != null) {
final BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.must(queryBuilder);
return boolQueryBuilder;
}
return queryBuilder;
}
}
/**
* In the simplest case, parse template string and variables from the request,
* compile the template and execute the template against the given variables.
*/
public static TemplateQueryBuilder fromXContent(QueryParseContext parseContext) throws IOException {
XContentParser parser = parseContext.parser();
Script template = Script.parse(parser, Script.DEFAULT_TEMPLATE_LANG);
// for deprecation of stored script namespaces the default lang is ignored,
// so the template lang must be set for a stored script
if (template.getType() == ScriptType.STORED) {
template = new Script(ScriptType.STORED, Script.DEFAULT_TEMPLATE_LANG, template.getIdOrCode(), template.getParams());
}
return new TemplateQueryBuilder(template);
}
}

View File

@ -21,7 +21,6 @@ package org.elasticsearch.script.mustache;
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.XContentType;
@ -289,15 +288,6 @@ public class SearchTemplateIT extends ESSingleNodeTestCase {
assertHitCount(searchResponse.getResponse(), 1);
assertWarnings("use of </lang/id> [/mustache/2] for looking up" +
" stored scripts/templates has been deprecated, use only <id> [2] instead");
Map<String, Object> vars = new HashMap<>();
vars.put("fieldParam", "bar");
TemplateQueryBuilder builder = new TemplateQueryBuilder("3", ScriptType.STORED, vars);
SearchResponse sr = client().prepareSearch().setQuery(builder)
.execute().actionGet();
assertHitCount(sr, 1);
assertWarnings("[template] query is deprecated, use search template api instead");
}
// Relates to #10397

View File

@ -1,229 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.script.mustache;
import org.apache.lucene.index.memory.MemoryIndex;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.test.AbstractQueryTestCase;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import static org.hamcrest.Matchers.containsString;
public class TemplateQueryBuilderTests extends AbstractQueryTestCase<TemplateQueryBuilder> {
/**
* The query type all template tests will be based on.
*/
private QueryBuilder templateBase;
/**
* All tests in this class cause deprecation warnings when a new {@link TemplateQueryBuilder} is created.
* Instead of having to check them in every single test, we do it after each test is run
*/
@After
public void checkWarning() {
assertWarnings("[template] query is deprecated, use search template api instead");
}
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return Arrays.asList(MustachePlugin.class, CustomScriptPlugin.class);
}
public static class CustomScriptPlugin extends MockScriptPlugin {
@Override
@SuppressWarnings("unchecked")
protected Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
scripts.put("{ \"match_all\" : {}}",
s -> new BytesArray("{ \"match_all\" : {}}"));
scripts.put("{ \"match_all\" : {\"_name\" : \"foobar\"}}",
s -> new BytesArray("{ \"match_all\" : {\"_name\" : \"foobar\"}}"));
scripts.put("{\n" +
" \"term\" : {\n" +
" \"foo\" : {\n" +
" \"value\" : \"bar\",\n" +
" \"boost\" : 2.0\n" +
" }\n" +
" }\n" +
"}", s -> new BytesArray("{\n" +
" \"term\" : {\n" +
" \"foo\" : {\n" +
" \"value\" : \"bar\",\n" +
" \"boost\" : 2.0\n" +
" }\n" +
" }\n" +
"}"));
return scripts;
}
}
@Before
public void setup() {
templateBase = new MatchQueryBuilder("field", "some values");
}
@Override
protected boolean supportsBoostAndQueryName() {
return false;
}
@Override
protected TemplateQueryBuilder doCreateTestQueryBuilder() {
return new TemplateQueryBuilder(new Script(ScriptType.INLINE, "mustache", templateBase.toString(), Collections.emptyMap()));
}
@Override
protected void doAssertLuceneQuery(TemplateQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException {
QueryShardContext queryShardContext = context.getQueryShardContext();
assertEquals(rewrite(QueryBuilder.rewriteQuery(templateBase, queryShardContext).toQuery(queryShardContext)), rewrite(query));
}
public void testIllegalArgument() {
expectThrows(IllegalArgumentException.class, () -> new TemplateQueryBuilder((Script) null));
}
/**
* Override superclass test since template query doesn't support boost and queryName, so
* we need to mutate other existing field in the test query.
*/
@Override
public void testUnknownField() throws IOException {
TemplateQueryBuilder testQuery = createTestQueryBuilder();
XContentType xContentType = randomFrom(XContentType.JSON, XContentType.YAML);
String testQueryAsString = toXContent(testQuery, xContentType).string();
String queryAsString = testQueryAsString.replace("inline", "bogusField");
try {
parseQuery(createParser(xContentType.xContent(), queryAsString));
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException e) {
assertThat(e.getMessage(), containsString("[script] unknown field [bogusField], parser not found"));
}
}
public void testJSONGeneration() throws IOException {
Map<String, Object> vars = new HashMap<>();
vars.put("template", "filled");
TemplateQueryBuilder builder = new TemplateQueryBuilder("I am a $template string", ScriptType.INLINE, vars);
XContentBuilder content = XContentFactory.jsonBuilder();
content.startObject();
builder.doXContent(content, null);
content.endObject();
content.close();
assertEquals("{\"template\":{\"inline\":\"I am a $template string\",\"lang\":\"mustache\",\"params\":{\"template\":\"filled\"}}}",
content.string());
}
public void testRawEscapedTemplate() throws IOException {
String expectedTemplateString = "{\"match_{{template}}\": {}}\"";
String query = "{\"template\": {\"inline\": \"{\\\"match_{{template}}\\\": {}}\\\"\",\"params\" : {\"template\" : \"all\"}}}";
Map<String, Object> params = new HashMap<>();
params.put("template", "all");
QueryBuilder expectedBuilder = new TemplateQueryBuilder(expectedTemplateString, ScriptType.INLINE, params);
assertParsedQuery(query, expectedBuilder);
}
public void testRawTemplate() throws IOException {
String expectedTemplateString = "{\"match_{{template}}\":{}}";
String query = "{\"template\": {\"inline\": {\"match_{{template}}\": {}},\"params\" : {\"template\" : \"all\"}}}";
Map<String, Object> params = new HashMap<>();
params.put("template", "all");
QueryBuilder expectedBuilder = new TemplateQueryBuilder(expectedTemplateString, ScriptType.INLINE, params, XContentType.JSON);
assertParsedQuery(query, expectedBuilder);
}
@Override
public void testMustRewrite() throws IOException {
String query = "{ \"match_all\" : {}}";
QueryBuilder builder = new TemplateQueryBuilder(new Script(ScriptType.INLINE, "mockscript", query,
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()), Collections.emptyMap()));
try {
builder.toQuery(createShardContext());
fail();
} catch (UnsupportedOperationException ex) {
assertEquals("this query must be rewritten first", ex.getMessage());
}
assertEquals(new MatchAllQueryBuilder(), builder.rewrite(createShardContext()));
}
public void testRewriteWithInnerName() throws IOException {
final String query = "{ \"match_all\" : {\"_name\" : \"foobar\"}}";
QueryBuilder builder = new TemplateQueryBuilder(new Script(ScriptType.INLINE, "mockscript", query,
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()), Collections.emptyMap()));
assertEquals(new MatchAllQueryBuilder().queryName("foobar"), builder.rewrite(createShardContext()));
builder = new TemplateQueryBuilder(new Script(ScriptType.INLINE, "mockscript", query, Collections.singletonMap(
Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()), Collections.emptyMap())).queryName("outer");
assertEquals(new BoolQueryBuilder().must(new MatchAllQueryBuilder().queryName("foobar")).queryName("outer"),
builder.rewrite(createShardContext()));
}
public void testRewriteWithInnerBoost() throws IOException {
final TermQueryBuilder query = new TermQueryBuilder("foo", "bar").boost(2);
QueryBuilder builder = new TemplateQueryBuilder(new Script(ScriptType.INLINE, "mockscript", query.toString(),
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()), Collections.emptyMap()));
assertEquals(query, builder.rewrite(createShardContext()));
builder = new TemplateQueryBuilder(new Script(ScriptType.INLINE, "mockscript", query.toString(),
Collections.singletonMap(Script.CONTENT_TYPE_OPTION, XContentType.JSON.mediaType()), Collections.emptyMap())).boost(3);
assertEquals(new BoolQueryBuilder().must(query).boost(3), builder.rewrite(createShardContext()));
}
@Override
protected Query rewrite(Query query) throws IOException {
// TemplateQueryBuilder adds some optimization if the template and query builder have boosts / query names that wraps
// the actual QueryBuilder that comes from the template into a BooleanQueryBuilder to give it an outer boost / name
// this causes some queries to be not exactly equal but equivalent such that we need to rewrite them before comparing.
if (query != null) {
MemoryIndex idx = new MemoryIndex();
return idx.createSearcher().rewrite(query);
}
return new MatchAllDocsQuery(); // null == *:*
}
}

View File

@ -1,96 +0,0 @@
---
"Template query":
- skip:
features: warnings
- do:
index:
index: test
type: testtype
id: 1
body: { "text": "value1" }
- do:
index:
index: test
type: testtype
id: 2
body: { "text": "value2 value3" }
- do:
indices.refresh: {}
- do:
put_template:
id: "1"
body: { "template": { "match": { "text": "{{my_value}}" } } }
- match: { acknowledged: true }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "inline": { "term": { "text": { "value": "{{template}}" } } }, "params": { "template": "value1" } } } }
- match: { hits.total: 1 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "file": "file_query_template", "params": { "my_value": "value1" } } } }
- match: { hits.total: 1 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "stored": "1", "params": { "my_value": "value1" } } } }
- match: { hits.total: 1 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "stored": "1", "params": { "my_value": "value1" } } } }
- match: { hits.total: 1 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "inline": {"match_{{template}}": {}}, "params" : { "template" : "all" } } } }
- match: { hits.total: 2 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "inline": "{ \"term\": { \"text\": { \"value\": \"{{template}}\" } } }", "params": { "template": "value1" } } } }
- match: { hits.total: 1 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "inline": "{\"match_{{template}}\": {}}", "params" : { "template" : "all" } } } }
- match: { hits.total: 2 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "inline": "{\"match_all\": {}}", "params" : {} } } }
- match: { hits.total: 2 }
- do:
warnings:
- '[template] query is deprecated, use search template api instead'
search:
body: { "query": { "template": { "inline": "{\"query_string\": { \"query\" : \"{{query}}\" }}", "params" : { "query" : "text:\"value2 value3\"" } } } }
- match: { hits.total: 1 }