默认值
使用 {{var}}{{^var}}default{{/var}}
的方式设置默认值。
示例:
{ "source": { "query": { "range": { "line_no": { "gte": "{{start}}", "lte": "{{end}}{{^end}}20{{/end}}" } } } }, "params": { ... } }
{{end}}{{^end}}20{{/end}}
就是给 end
设置了默认值为 20 。
当 params
是 { "start": 10, "end": 15 }
时,渲染结果是:
{ "range": { "line_no": { "gte": "10", "lte": "15" } } }
当 params
是 { "start": 10 }
时,end 就会使用默认值,渲染结果就是:
{ "range": { "line_no": { "gte": "10", "lte": "20" } } }
条件子句
有时候我们的参数是可选的,这时候就可以使用 {{#key}} {{/key}}
的语法。
示例,假设参数 line_no
, start
, end
都是可选的,使用 {{#key}} {{/key}}
形如:
{ "query": { "bool": { "must": { "match": { "line": "{{text}}" } }, "filter": { {{#line_no}} "range": { "line_no": { {{#start}} "gte": "{{start}}" {{#end}},{{/end}} {{/start}} {{#end}} "lte": "{{end}}" {{/end}} } } {{/line_no}} } } } }
1、 当参数为:
{ "params": { "text": "words to search for", "line_no": { "start": 10, "end": 20 } } }
渲染结果是:
{ "query": { "bool": { "must": { "match": { "line": "words to search for" } }, "filter": { "range": { "line_no": { "gte": "10", "lte": "20" } } } } } }
2、 当参数为:
{ "params": { "text": "words to search for" } }
渲染结果为:
{ "query": { "bool": { "must": { "match": { "line": "words to search for" } }, "filter": {} } } }
3、当参数为:
{ "params": { "text": "words to search for", "line_no": { "start": 10 } } }
渲染结果为:
{ "query": { "bool": { "must": { "match": { "line": "words to search for" } }, "filter": { "range": { "line_no": { "gte": 10 } } } } } }
4、当参数为:
{ "params": { "text": "words to search for", "line_no": { "end": 20 } } }
渲染结果为:
{ "query": { "bool": { "must": { "match": { "line": "words to search for" } }, "filter": { "range": { "line_no": { "lte": 20 } } } } } }
需要注意的是在 JSON 对象中,
{ "filter": { {{#line_no}} ... {{/line_no}} } }
这样直接写 {{#line_no}}
肯定是非法的JSON格式,你必须转换为 JSON 字符串。
URLs 编码
使用 {{#url}}value{{/url}}
的方式可以进行 HTML 编码转义。
示例:
GET _render/template { "source": { "query": { "term": { "http_access_log": "{{#url}}{{host}}/{{page}}{{/url}}" } } }, "params": { "host": "https://www.elastic.co/", "page": "learn" } }
渲染结果:
{ "template_output": { "query": { "term": { "http_access_log": "https%3A%2F%2Fwww.elastic.co%2F%2Flearn" } } } }
Mustache 基本语法
上文中的 {{ }}
语法其实就是 mustache language ,补充介绍下基本的语法规则。
使用 {{key}}
模板:Hello {{name}}
输入:
{ "name": "Chris" }
输出:Hello Chris
使用 {{{key}}}
避免转义
所有变量都会默认进行 HTML 转义。
模板:{{company}}
输入:
{ "company": "<b>GitHub</b>" }
输出:<b>GitHub</b>
使用 {{{ }}}
避免转义。
模板:{{{company}}}
输入:
{ "company": "<b>GitHub</b>" }
输出:GitHub
使用 {{#key}} {{/key}}
构造区块
1、 当 key 是 false 或者空列表将会忽略 模板:
Shown. {{#person}} Never shown! {{/person}}
输入:
{ "person": false }
输出:
Shown.
2、 当 key 非空值则渲染填充 模板:
{{#repo}} <b>{{name}}</b> {{/repo}}
输入:
{ "repo": [ { "name": "resque" }, { "name": "hub" }, { "name": "rip" } ] }
输出:
<b>resque</b> <b>hub</b> <b>rip</b>
3、当 key 是函数则调用后渲染 模板:
{{#wrapped}} {{name}} is awesome. {{/wrapped}}
输入:
{ "name": "Willy", "wrapped": function() { return function(text, render) { return "<b>" + render(text) + "</b>" } } }
输出:
<b>Willy is awesome.</b>
4、当 key 是非 false 且非列表 模板:
{{#person?}} Hi {{name}}! {{/person?}}
输入:
{ "person?": { "name": "Jon" } }
输出:
Hi Jon!
使用 {{^key}} {{/key}}
构造反区块
{{^key}} {{/key}}
的语法与 {{#key}} {{/key}}
类似,不同的是,当 key 不存在,或者是 false ,又或者是空列表时才渲染输出区块内容。
模板:
{{#repo}} <b>{{name}}</b> {{/repo}} {{^repo}} No repos :( {{/repo}}
输入:
{ "repo": [] }
输出:
No repos :(
使用 {{! }}
添加注释
{{! }}
注释内容将会被忽略。
模板:
<h1>Today{{! ignore me }}.</h1>
输出:
<h1>Today.</h1>
使用 {{> }}
子模块
模板:
base.mustache: <h2>Names</h2> {{#names}} {{> user}} {{/names}} user.mustache: <strong>{{name}}</strong>
其实也就等价于:
<h2>Names</h2> {{#names}} <strong>{{name}}</strong> {{/names}}
使用 {{= =}}
自定义定界符
有时候我们需要改变默认的定界符 {{ }}
,那么就可以使用 {{= =}}
的方式自定义定界符。
例如:
{{=<% %>=}}
定界符被定义为了 <% %>
,这样原先 {{key}}
的使用方式就变成了 <%key%>
。再使用:
<%={{ }}=%>
就重新把定界符改回了 {{ }}
。
更多语法详情请查阅官方文档 mustache language 。
结语
使用 search template 可以对搜索进行有效的解耦,即应用程序只需要关注搜索参数与返回结果,而不用关注具体使用的 DSL 查询语句,到底使用哪种 DSL 则由搜索模板进行单独管理。