共计 6035 个字符,预计需要花费 16 分钟才能阅读完成。
ES Search Template
所谓 search template 搜寻模板其实就是:
- 事后定义好查问语句 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"}
}
}
在模板中通过 {{}}
的形式预留参数,而后查问时再指定对应的参数值,最初填充成具体的查问语句进行搜寻。
搜寻模板 API
为了实现搜寻模板和查问拆散,咱们首先须要独自保留和治理搜寻模板。
保留搜寻模板
应用 scripts API 保留搜寻模板(不存在则创立,存在则笼罩)。示例:
POST _scripts/<templateid>
{
"script": {
"lang": "mustache",
"source": {
"query": {
"match": {"title": "{{query_string}}"
}
}
}
}
}
查问搜寻模板
GET _scripts/<templateid>
删除搜寻模板
DELETE _scripts/<templateid>
应用搜寻模板
示例:
GET _search/template
{
"id": "<templateid>",
"params": {"query_string": "search words"}
}
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/<template_name>
{
"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": "search words"}
}
渲染进去的 DSL 就是:
{
"query": {
"term": {"message": "search words"}
}
}
将参数转换为 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"
]
}
}
}
对象数组的渲染示例:
GET _search/template
{"source": "{\"query\":{\"bool\":{\"must\": {{#toJson}}clauses{{/toJson}} }}}",
"params": {
"clauses": [{ "term": { "user" : "foo"} },
{"term": { "user" : "bar"} }
]
}
}
渲染后果就是:
{
"query": {
"bool": {
"must": [{ "term": { "user" : "foo"} },
{"term": { "user" : "bar"} }
]
}
}
}
将数组 join 成字符串
应用 {{#join}}array{{/join}}
能够将数组 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": "{{#join delimiter='||'}}date.formats{{/join delimiter='||'}}"
}
}
}
},
"params": {
"date": {
"min": "2016",
"max": "31/12/2017",
"formats": ["dd/MM/yyyy", "yyyy"]
}
}
}
例子中的 {{#join delimiter='||'}} {{/join delimiter='||'}}
意思就是进行 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": "{{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>"}
输入:<b>GitHub</b>
应用 {{#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 则由搜寻模板进行独自治理。