The /_search/template
endpoint allows to use the mustache language to pre render search requests,
before they are executed and fill existing templates with template parameters.
GET _search/template { "source" : { "query": { "match" : { "{{my_field}}" : "{{my_value}}" } }, "size" : "{{my_size}}" }, "params" : { "my_field" : "message", "my_value" : "some message", "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 of the mustache project.
The mustache language is implemented in Elasticsearch as a sandboxed scripting language, hence it obeys settings that may be used to enable or disable scripts per type and context as described in the scripting docs
GET _search/template { "source": { "query": { "term": { "message": "{{query_string}}" } } }, "params": { "query_string": "search for these words" } }
The {{#toJson}}parameter{{/toJson}}
function can be used to convert parameters
like maps and array to their JSON representation:
GET _search/template { "source": "{ \"query\": { \"terms\": {{#toJson}}statuses{{/toJson}} }}", "params": { "statuses" : { "status": [ "pending", "published" ] } } }
which is rendered as:
{ "query": { "terms": { "status": [ "pending", "published" ] } } }
A more complex example substitutes an array of JSON objects:
GET _search/template { "source": "{\"query\":{\"bool\":{\"must\": {{#toJson}}clauses{{/toJson}} }}}", "params": { "clauses": [ { "term": { "user" : "foo" } }, { "term": { "user" : "bar" } } ] } }
which is rendered as:
{ "query" : { "bool" : { "must" : [ { "term" : { "user" : "foo" } }, { "term" : { "user" : "bar" } } ] } } }
The {{#join}}array{{/join}}
function can be used to concatenate the
values of an array as a comma delimited string:
GET _search/template { "source": { "query": { "match": { "emails": "{{#join}}emails{{/join}}" } } }, "params": { "emails": [ "username@email.com", "lastname@email.com" ] } }
which is rendered as:
{ "query" : { "match" : { "emails" : "username@email.com,lastname@email.com" } } }
The function also accepts a custom delimiter:
GET _search/template { "source": { "query": { "range": { "born": { "gte" : "{{date.min}}", "lte" : "{{date.max}}", "format": "{{#join delimiter='||'}}date.formats{{/join delimiter='||'}}" } } } }, "params": { "date": { "min": "2016", "max": "31/12/2017", "formats": ["dd/MM/yyyy", "yyyy"] } } }
which is rendered as:
{ "query" : { "range" : { "born" : { "gte" : "2016", "lte" : "31/12/2017", "format" : "dd/MM/yyyy||yyyy" } } } }
A default value is written as {{var}}{{^var}}default{{/var}}
for instance:
{ "source": { "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:
{ "range": { "line_no": { "gte": "10", "lte": "15" } } }
But when params
is { "start": 10 }
this query would use the default value
for end
:
{ "range": { "line_no": { "gte": "10", "lte": "20" } } }
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:
We could write the query as:
{ "query": { "bool": { "must": { "match": { "line": "{{text}}" } }, "filter": { {{#line_no}} "range": { "line_no": { {{#start}} "gte": "{{start}}" {{#end}},{{/end}} {{/start}} {{#end}} "lte": "{{end}}" {{/end}} } } {{/line_no}} } } } }
Fill in the value of param | |
Include the | |
Include the | |
Fill in the value of param | |
Add a comma after the | |
Include the | |
Fill in the value of param |
As written above, this template is not valid JSON because it includes the
section markers like {{#line_no}}
. For this reason, the template should
either be stored in a file (see Pre-registered template) or, when used
via the REST API, should be written as a string:
"source": "{\"query\":{\"bool\":{\"must\":{\"match\":{\"line\":\"{{text}}\"}},\"filter\":{{{#line_no}}\"range\":{\"line_no\":{{{#start}}\"gte\":\"{{start}}\"{{#end}},{{/end}}{{/start}}{{#end}}\"lte\":\"{{end}}\"{{/end}}}}{{/line_no}}}}}}"
The {{#url}}value{{/url}}
function can be used to encode a string value
in a HTML encoding form as defined in by the HTML specification.
As an example, it is useful to encode a URL:
GET _render/template { "source" : { "query" : { "term": { "http_access_log": "{{#url}}{{host}}/{{page}}{{/url}}" } } }, "params": { "host": "https://www.elastic.co/", "page": "learn" } }
The previous query will be rendered as:
{ "template_output" : { "query" : { "term" : { "http_access_log" : "https%3A%2F%2Fwww.elastic.co%2F%2Flearn" } } } }
You can register search templates by using the stored scripts api.
POST _scripts/<templatename> { "script": { "lang": "mustache", "source": { "query": { "match": { "title": "{{query_string}}" } } } } }
This template can be retrieved by
GET _scripts/<templatename>
which is rendered as:
{ "script" : { "lang" : "mustache", "source" : "{\"query\":{\"match\":{\"title\":\"{{query_string}}\"}}}", "options": { "content_type" : "application/json; charset=UTF-8" } }, "_id": "<templatename>", "found": true }
This template can be deleted by
DELETE _scripts/<templatename>
To use a stored template at search time use:
GET _search/template { "id": "<templateName>", "params": { "query_string": "search for these words" } }
A template can be rendered in a response with given parameters using
GET _render/template { "source": "{ \"query\": { \"terms\": {{#toJson}}statuses{{/toJson}} }}", "params": { "statuses" : { "status": [ "pending", "published" ] } } }
This call will return the rendered template:
Pre-registered templates can also be rendered using
GET _render/template/<template_name> { "params": { "..." } }
You can use explain
parameter when running a template:
GET _search/template { "id": "my_template", "params": { "status": [ "pending", "published" ] }, "explain": true }
You can use profile
parameter when running a template:
GET _search/template { "id": "my_template", "params": { "status": [ "pending", "published" ] }, "profile": true }