Search template examples with Mustacheedit

The mustache templating language defines various tag types you can use within templates. The following sections describe some of these tag types and provide examples of using them in Elasticsearch search templates.

Mustache variablesedit

Mustache tags are typically enclosed in double curly brackets. A mustache variable: {{my-variable}} is a type of mustache tag. When you run a templated search, Elasticsearch replaces these variables with values from params.

For example, consider the following search template:

PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source": {
      "query": {
        "match": {
          "message": "{{query_string}}"
        }
      },
      "from": "{{from}}",
      "size": "{{size}}"
    }
  }
}

Testing the above search template with params:

response = client.render_search_template(
  body: {
    id: 'my-search-template',
    params: {
      query_string: 'hello world',
      from: 20,
      size: 10
    }
  }
)
puts response
POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "hello world",
    "from": 20,
    "size": 10
  }
}

When rendered, the {{query_string}} in message is replaced with hello world passed in params.

{
  "template_output": {
    "query": {
      "match": {
        "message": "hello world"
      }
    },
    "from": "20",
    "size": "10"
  }
}

If your search template doesn’t pass a value to your query_string the message would be replaced with a empty string.

For example:

POST _render/template
{
  "id": "my-search-template",
  "params": {
    "from": 20,
    "size": 10
  }
}

When rendered, template outputs as:

{
  "template_output": {
    "query": {
      "match": {
        "message": ""
      }
    },
    "from": "20",
    "size": "10"
  }
}

Sectionsedit

Sections are also a type of Mustache tags. You can use sections in your search template with a nested or unnested object. A section begins with {{#my-section-variable}} and ends with {{/my-section-variable}}.

The following search template shows an example using sections with nested objects:

POST _render/template
{
  "source":
  """
  {
    "query": {
      "match": {
        {{#query_message}}
          {{#query_string}}
        "message": "Hello {{#first_name_section}}{{first_name}}{{/first_name_section}} {{#last_name_section}}{{last_name}}{{/last_name_section}}"
          {{/query_string}}
        {{/query_message}}
      }
    }
  }
  """,
  "params": {
    "query_message": {
       "query_string": {
         "first_name_section": {"first_name": "John"},
         "last_name_section": {"last_name": "kimchy"}
       }
    }
  }
}

The template renders as:

{
  "template_output": {
    "query": {
      "match": {
        "message": "Hello John kimchy"
      }
    }
  }
}

Listsedit

You can pass a list of objects and loop over each item in your search template.

For example, following search template combines sections and matches all the usernames:

PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source": {
      "query":{
        "multi-match":{
          "query": "{{query_string}}",
          "fields": """[{{#text_fields}}{{user_name}},{{/text_fields}}]"""
        }
      }
    }
  }
}

Testing the template:

POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "My string",
    "text_fields": [
      {
        "user_name": "John"
      },
      {
        "user_name": "kimchy"
      }
    ]
  }
}

When rendered, template outputs:

{
  "template_output": {
    "query": {
      "multi-match": {
        "query": "My string",
        "fields": "[John,kimchy,]"
      }
    }
  }
}

The above will cause a trailing comma issue, which causes invalid JSON. A workaround would be to include an inverted section and adding a variable to make sure it’s the last item in the array.

For example:

PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source": {
      "query":{
        "multi-match":{
          "query": "{{query_string}}",
          "fields": """[{{#text_fields}}{{user_name}}{{^last}},{{/last}}{{/text_fields}}]"""
        }
      }
    }
  }
}

Testing the my-search-template again with a variable: last to determine it’s the last item in the array:

POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "My string",
    "text_fields": [
      {
        "user_name": "John",
        "last": false
      },
      {
        "user_name": "kimchy",
        "last": true
      }
    ]
  }
}

When rendered the template outputs:

{
  "template_output": {
    "query": {
      "multi-match": {
        "query": "My string",
        "fields": "[John,kimchy]"
      }
    }
  }
}

Lambdasedit

Elasticsearch has pre-built custom functions to support converting the text into a specific format.

To Learn more about usage of mustache lambdas, check out the examples in Url encode strings, Concatenate values, and Convert to json.

Inverted sectionsedit

Inverted sections are useful when you want to set a value once.

To use inverted sections use following syntax:

{{^my-variable}} content {{/my-variable}}

For example, in the following search template if name_exists is false, message is set with Hello World, else it is set to empty string.

POST _render/template
{
  "source": {
    "query": {
      "match": {
        "message": "{{^name_exists}}Hello World{{/name_exists}}"
      }
    }
  },
  "params": {
     "name_exists": false
  }
}

They can also be combined with conditions and default values.

For example, in the following search template, if name_exists is true, the value of {{query_string}} is replaced. If name_exists is false, it is set to the default value World.

POST _render/template
{
  "source": {
    "query": {
      "match": {
        "message": "Hello {{#name_exists}}{{query_string}}{{/name_exists}}{{^name_exists}}World{{/name_exists}}"
      }
    }
  },
  "params": {
    "query_string": "Kimchy",
     "name_exists": true
  }
}

When rendered, template output:

{
  "template_output": {
    "query": {
      "match": {
        "message": "Hello Kimchy"
      }
    }
  }
}

Set delimiteredit

You can change the default delimiter: double curly brackets {{my-variable}} to any custom delimiter in your search template.

For example, the following search template changes the default delimiter to a single round bracket (query_string).

PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source":
    """
    {
      "query": {
        "match": {
           {{=( )=}}
          "message": "(query_string)"
          (={{ }}=)
        }
      }
    }
    """
  }
}

Testing the template with new delimiter:

POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "hello world"
  }
}

When rendered, template outputs:

{
  "template_output": {
    "query": {
      "match": {
        "message": "hello world"
      }
    }
  }
}

Unsupported featuresedit

The following mustache features are not supported in Elasticsearch search templates:

  • Partials