Skip to content

Commit

Permalink
Query Templates: Adding dedicated /_search/template endpoint
Browse files Browse the repository at this point in the history
In order to simplify query template execution an own endpoint has been added

Closes #5353
  • Loading branch information
spinscale authored and s1monw committed Mar 20, 2014
1 parent 33caa10 commit 6977479
Show file tree
Hide file tree
Showing 12 changed files with 601 additions and 100 deletions.
225 changes: 210 additions & 15 deletions docs/reference/query-dsl/queries/template-query.asciidoc
Expand Up @@ -8,7 +8,7 @@ template parameters.

[source,js]
------------------------------------------
GET _search
GET /_search
{
"query": {
"template": {
Expand All @@ -23,34 +23,37 @@ GET _search
------------------------------------------


Alternatively escaping the template works as well:
Alternatively passing the template as an escaped string works as well:

[source,js]
------------------------------------------
GET _search
GET /_search
{
"query": {
"template": {
"query": "{\"match_{{template}}\": {}}\"",
"query": "{\"match_{{template}}\": {}}\"", <1>
"params" : {
"template" : "all"
}
}
}
}
------------------------------------------
<1> New line characters (`\n`) should be escaped as `\\n` or removed,
and quotes (`"`) should be escaped as `\\"`.

You register a template by storing it in the conf/scripts directory of
elasticsearch. In order to execute the stored template reference it in the query parameters:
You can register a template by storing it in the `config/scripts` directory.
In order to execute the stored template, reference it by name in the `query`
parameter:


[source,js]
------------------------------------------
GET _search
GET /_search
{
"query": {
"template": {
"query": "storedTemplate",
"query": "storedTemplate", <1>
"params" : {
"template" : "all"
}
Expand All @@ -59,7 +62,7 @@ GET _search
}
------------------------------------------

<1> Name of the the query template in `config/scripts/`.

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
Expand All @@ -68,7 +71,7 @@ values:

[source,js]
------------------------------------------
GET _search
GET /_search
{
"query": {
"template": {
Expand All @@ -79,23 +82,215 @@ GET _search
}
}
}
------------------------------------------

which is then turned into:

[source,js]
------------------------------------------
GET _search
{
"query": {
"match_all": {}
"match_all": {}
}
}
------------------------------------------

There is also a dedicated `template` endpoint, which allows you to specify the template query directly.
You can use the `/_search/template` endpoint for that.

[source,js]
------------------------------------------
GET /_search/template
{
"template" : {
"query": { "match" : { "{{my_field}}" : "{{my_value}}" } },
"size" : {{my_size}}
},
"params" : {
"my_field" : "foo",
"my_value" : "bar",
"my_size" : 5
}
}
------------------------------------------


For more information on how Mustache templating and what kind of templating you
can do with it check out the [online
documentation](http://mustache.github.io/mustache.5.html) of the mustache project.
can do with it check out the http://mustache.github.io/mustache.5.html[online
documentation of the mustache project].

[float]
==== More template examples

[float]
===== Filling in a query string with a single value

[source,js]
------------------------------------------
GET /_search/template
{
"template": {
"query": {
"match": {
"title": "{{query_string}}"
}
}
},
"params": {
"query_string": "search for these words"
}
}
------------------------------------------

[float]
===== Passing an array of strings

[source,js]
------------------------------------------
GET /_search/template
{
"template": {
"query": {
"terms": {
"status": [
"{{#status}}",
"{{.}}",
"{{/status}}"
]
}
}
},
"params": {
"status": [ "pending", "published" ]
}
}
------------------------------------------

which is rendered as:

[source,js]
------------------------------------------
{
"query": {
"terms": {
"status": [ "pending", "published" ]
}
}
------------------------------------------

[float]
===== Default values

A default value is written as `{{var}}{{^var}}default{{/var}}` for instance:

[source,js]
------------------------------------------
{
"template": {
"query": {
"range": {
"line_no": {
"gte": "{{start}}",
"lte": "{{end}}{{^end}}20{{/end}}"
}
}
}
},
"params": { ... }
}
------------------------------------------

When `params` is `{ "start": 10, "end": 15 }` this query would be rendered as:

[source,js]
------------------------------------------
{
"range": {
"line_no": {
"gte": "10",
"lte": "15"
}
}
}
------------------------------------------

But when `params` is `{ "start": 10 }` this query would use the default value
for `end`:

[source,js]
------------------------------------------
{
"range": {
"line_no": {
"gte": "10",
"lte": "20"
}
}
}
------------------------------------------

[float]
===== Conditional clauses

Conditional clauses cannot be expressed using the JSON form of the template.
Instead, the template *must* be passed as a string. For instance, let's say
we wanted to run a `match` query on the `line` field, and optionally wanted
to filter by line numbers, where `start` and `end` are optional.

The `params` would look like:
[source,js]
------------------------------------------
{
"params": {
"text": "words to search for",
"line_no": { <1>
"start": 10, <1>
"end": 20 <1>
}
}
}
------------------------------------------
<1> All three of these elements are optional.

We could write the query as:

[source,js]
------------------------------------------
{
"filtered": {
"query": {
"match": {
"line": "{{text}}" <1>
}
},
"filter": {
{{#line_no}} <2>
"range": {
"line_no": {
{{#start}} <3>
"gte": "{{start}}" <4>
{{#end}},{{/end}} <5>
{{/start}} <3>
{{#end}} <6>
"lte": "{{end}}" <7>
{{/end}} </6>
}
}
{{/line_no}} <2>
}
}
}
------------------------------------------
<1> Fill in the value of param `text`
<2> Include the `range` filter only if `line_no` is specified
<3> Include the `gte` clause only if `line_no.start` is specified
<4> Fill in the value of param `line_no.start`
<5> Add a comma after the `gte` clause only if `line_no.start`
AND `line_no.end` are specified
<6> Include the `lte` clause only if `line_no.end` is specified
<7> Fill in the value of param `line_no.end`

As written above, this template is not valid JSON because it includes the
_section_ markers like `{{#line_no}}`. For this reason, the template
can only be written as a string.

23 changes: 23 additions & 0 deletions rest-api-spec/api/search.template.json
@@ -0,0 +1,23 @@
{
"search-template": {
"documentation": "http://www.elasticsearch.org/guide/en/elasticsearch/reference/master/search-search.html",
"methods": ["GET", "POST"],
"url": {
"path": "/_search/template",
"paths": ["/_search/template", "/{index}/_search/template", "/{index}/{type}/_search/template"],
"parts": {
"index": {
"type" : "list",
"description" : "A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices"
},
"type": {
"type" : "list",
"description" : "A comma-separated list of document types to search; leave empty to perform the operation on all types"
}
}
},
"body": {
"description": "The search definition template and its params"
}
}
}
29 changes: 29 additions & 0 deletions rest-api-spec/test/search/40_search_request_template.yaml
@@ -0,0 +1,29 @@
---
"Template search request":

- do:
index:
index: test
type: testtype
id: 1
body: { "text": "value1" }
- do:
index:
index: test
type: testtype
id: 2
body: { "text": "value2" }
- do:
indices.refresh: {}

- do:
search-template:
body: { "template" : { "query": { "term": { "text": { "value": "{{template}}" } } } }, "params": { "template": "value1" } }

- match: { hits.total: 1 }

- do:
search-template:
body: { "template" : { "query": { "match_{{template}}": {} } }, "params" : { "template" : "all" } }

- match: { hits.total: 2 }

0 comments on commit 6977479

Please sign in to comment.