ESSearchTemplate所谓搜索模板搜索模板其实就是:预先定义好查询语句DSL的结构并预留搜索用的参数,然后将参数值传入到渲染完整的DSL,最后可以使用搜索模板进行搜索DSL与应用程序解耦,可以更灵活地更改查询语句。例如:GET_search/template{"source":{"query":{"match":{"{{my_field}}":"{{my_value}}"}}},"params":{"my_field":"message","my_value":"foo"}}构建的DSL是:{"query":{"match":{"message":"foo"}}}在模板中通过{{}}预留parameters,然后在查询的时候指定对应的参数值,最后填写具体的查询语句进行查找。SearchTemplateAPI为了实现搜索模板和查询的分离,我们首先需要对搜索模板进行单独保存和管理。保存搜索模板使用scriptsAPI保存搜索模板(不存在则创建,存在则覆盖)。示例:POST_scripts/{"script":{"lang":"mustache","source":{"query":{"match":{"title":"{{query_string}}"}}}}}查询搜索模板GET_scripts/删除搜索模板DELETE_scripts/使用搜索模板示例:GET_search/template{"id":"","params":{"query_string":"searchwords"}}params中的参数与搜索模板中定义的一致。上面保存搜索模板的例子是{{query_string}},所以这里搜索时对应的参数是query_string。检查搜索模板有时我们想看看在搜索模板有输入参数后呈现的DSL是什么样子的。示例:GET_render/template{"source":"{\"query\":{\"terms\":{{#toJson}}statuses{{/toJson}}}}","params":{"statuses":{"status":["pending","published"]}}}返回结果为:{"template_output":{"query":{"terms":{"status":["pending","published"]}}}}{{#toJson}}{{/toJson}}转换为json格式。可以通过以下方式查看保存的搜索模板:GET_render/template/{"params":{"..."}}使用explain和profile参数的示例:GET_search/template{"id":"my_template","params":{"status":["pending","published"]},"explain":true}GET_search/template{"id":"my_template","params":{"status":["pending","published"]},"profile":true}模板渲染填充简单值GET_search/template{"source":{"query":{"term":{"message":"{{query_string}}"}}},"params":{"query_string":"searchwords"}}呈现的DSL是:{"query":{"term":{"message":"searchwords"}}}将参数转换为JSON使用{{#toJson}}parameter{{/toJson}}会将参数转换为JSON。GET_search/template{"source":"{\"query\":{\"terms\":{{#toJson}}statuses{{/toJson}}}}","params":{"statuses":{"status":["pending","published"]}}}呈现的DSL是:{"query":{"terms":{"status":["pending","published"]}}}Example对象数组的渲染:GET_search/template{"source":"{\"query\":{\"bool\":{\"must\":{{#toJson}}clauses{{/toJson}}}}}","params":{"clauses":[{"term":{"user":"foo"}},{"term":{"user":"bar"}}]}}render结果是:{"query":{"bool":{"must":[{"term":{"user":"foo"}},{"term":{"user":"bar"}}]}}}将数组连接成字符串使用{{#join}}array{{/join}}将数组连接成字符串。示例:GET_search/template{"source":{"query":{"match":{"emails":"{{#join}}emails{{/join}}"}}},"params":{"emails":["aaa","bbb"]}}渲染结果:{"query":{"match":{"emails":"aaa,bbb"}}}除了被分隔,默认,也可以自定义分隔符,例如:{"source":{"query":{"range":{"born":{"gte":"{{date.min}}","lte":"{{date.max}}","format":"{{#joindelimiter='||'}}date.formats{{/joindelimiter='||'}}"}}}},"params":{"date":{"min":"2016","max":"31/12/2017","formats":["dd/MM/yyyy","yyyy"]}}}{{#in例子joindelimiter='||'}}{{/joindelimiter='||'}}表示执行join操作,分隔符设置为||,渲染结果为:{"query":{"range":{"born":{"gte":"2016","lte":"31/12/2017","format":"dd/MM/yyyy||yyyy"}}}}默认值使用{{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":"{{开始}}"{{#end}},{{/end}}{{/start}}{{#end}}"lte":"{{end}}"{{/end}}}}{{/line_no}}}}}}1。当参数为:{"params":{"text":"wordstosearchfor","line_no":{"start":10,"end":20}}}渲染结果为:{"query":{“bool”:{“必须”:{“匹配”:{“行”:“要搜索的词”}},“过滤器”:{“范围”:{“line_no”:{“gte”:“10","lte":"20"}}}}}}2.当参数为:{"params":{"text":"wordstosearchfor"}}渲染结果For:{"query":{“布尔”:{"must":{"match":{"line":"wordstosearchfor"}},"filter":{}}}}3.当参数为:{"params":{"text":"wordstosearchfor","line_no":{"start":10}}}渲染结果为:{"query":{"bool":{"must":{"match":{"line":"wordstosearchfor"}},"filter":{"range":{"line_no":{"gte":10}}}}}}4.当参数为:{"params":{"text":"wordstosearchfor","line_no":{"end":20}}}渲染结果为:{"query":{"bool":{"must":{"match":{"line":"wordstosearchfor"}},"filter":{"range":{"line_no":{"lte":20}}}}}}需要注意的是,在JSON对象中,{"filter":{{{#line_no}}...{{/line_no}}}}直接写{{#line_no}}肯定是非法的JSON格式,必须使用{{#url}}值转成JSON字符串编码的URL{{/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语言。让我介绍一下基本的语法规则。使用{{key}}模板:Hello{{name}}输入:{"name":"Chris"}输出:HelloChris避免使用{{{key}}}转义默认情况下,所有变量都是HTML转义的。模板:{{company}}输入:{"company":"GitHub"}输出:GitHub使用{{{}}}避免转义。模板:{{{company}}}输入:{"company":"GitHub"}输出:GitHub使用{{#key}}{{/key}}构造块1.当key为false或为空列表时,模板将被忽略:显示。{{#person}}从未出现过!{{/person}}输入:{"person":false}输出:显示。2.当key不为空时,模板会被渲染:{{#repo}}{{name}}{{/repo}}Input:{"repo":[{"name":"resque"},{"name":"hub"},{"name":"rip"}]}output:resquehubrip3、当key为函数时,调用{{#wrapped}}{{name}}后模板渲染,真棒。{{/wrapped}}输入:{"name":"Willy","wrapped":function(){returnfunction(text,render){return""+render(text)+""}}}输出:Willyisawesome.4.当密钥不是false且不是列表时模板:{{#person?}}嗨{{name}}!{{/person?}}输入:{"person?":{"name":"Jon"}}输出:嗨,乔恩!使用{{^key}}{{/key}}构造反向块{{^key}}{{/key}}语法类似于{{#key}}{{/key}},不同的是输出块内容模板只有当key不存在,或者为false,或者是一个空列表:{{#repo}}{{name}}{{/repo}}{{^repo}}没有repos:({{/repo}}输入:{"repo":[]}输出:无回购:(使用{{!}}添加评论{{!}}评论内容将被忽略。模板:今天{{!忽略我}}。
输出:今天。
使用{{>}}子模块模板:base.mustache:Names
{{#names}}{{>user}}{{/names}}user.mustache:{{name}}实际上等同于:Names
{{#names}}{{name}}{{/names}}使用{{==}}自定义分隔符有时我们需要更改默认分隔符{{}},这时我们可以使用{{==}}自定义分隔符。例如:{{=<%%>=}}分隔符定义为<%%>,所以原来的{{key}}用法变成了<%key%>。再次使用:<%={{}}=%>将分隔符改回{{}}.更多语法细节请参考官方文档mustachelanguage。结论使用搜索模板可以有效解耦搜索,即应用只需要关注搜索参数和返回结果,而不用关注具体使用的DSL查询语句,使用哪个DSL由搜索模板。