文章目录
ElasticSearch检索你的数据(六)
搜索模板
搜索模板存储了运行不同变量的查询模板。如果你使用ElasticSearch作为查询后端,你可以将来自搜索栏的用户输入传递给搜索模板的变量参数。这可以让你在不公开ElasticSearch查询语法的情况下来运行查询。
如果自定义的应用使用了ElasticSearch,那么查询模板可以在不修改你应用代码的情况下修改ElasticSearch的搜索。
创建一个搜索模板
对于创建和修改搜索模板,你可以使用create stored script API
。
请求的source
支持与搜索API的请求体一样的参数。source
也支持Mustache
变量,通常用两个大括号括起来:{{my-var}}
。当你运行模板搜索的时候,ElasticSearch会用param
的值替换这个变量。
搜索模板必须使用一个 "lang":"mustache"
。
以下请求创建一个id
为my-search-template
的搜索模板。
curl -X PUT "localhost:9200/_scripts/my-search-template?pretty" -H 'Content-Type: application/json' -d'
{
"script": {
"lang": "mustache",
"source": {
"query": {
"match": {
"message": "{{query_string}}"
}
},
"from": "{{from}}",
"size": "{{size}}"
},
"params": {
"query_string": "My query string"
}
}
}
'
Elasticsearch 将搜索模板存储为集群状态下的 Mustache
脚本。 Elasticsearch 在模板脚本上下文中编译搜索模板。限制或禁用脚本的设置也会影响搜索模板。
验证一个搜索模板
使用render search template API
利用不同的param
测试搜索模板
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"id": "my-search-template",
"params": {
"query_string": "hello world",
"from": 20,
"size": 10
}
}
'
当参数被渲染的时候,模板会输出搜索请求体。
{
"template_output": {
"query": {
"match": {
"message": "hello world"
}
},
"from": "20",
"size": "10"
}
}
您还可以使用 API 来测试内联模板。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"query": {
"match": {
"message": "{{query_string}}"
}
},
"from": "{{from}}",
"size": "{{size}}"
},
"params": {
"query_string": "hello world",
"from": 20,
"size": 10
}
}
'
运行一个模板搜索
使用search template API
来运行一个使用搜索模板的搜索。你可以为每个请求指定不同的param
。
curl -X GET "localhost:9200/my-index/_search/template?pretty" -H 'Content-Type: application/json' -d'
{
"id": "my-search-template",
"params": {
"query_string": "hello world",
"from": 0,
"size": 10
}
}
'
响应使用与search API
响应一样的属性。
{
"took": 36,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.5753642,
"hits": [
{
"_index": "my-index",
"_type": "_doc",
"_id": "1",
"_score": 0.5753642,
"_source": {
"message": "hello world"
}
}
]
}
}
运行多个模板搜索
使用multi search template API
在一个单独的请求中运行多个模板搜索。与多个单独搜索相比,这些请求的开销通常更少,速度更快。
curl -X GET "localhost:9200/my-index/_msearch/template?pretty" -H 'Content-Type: application/json' -d'
{ }
{ "id": "my-search-template", "params": { "query_string": "hello world", "from": 0, "size": 10 }}
{ }
{ "id": "my-other-search-template", "params": { "query_type": "match_all" }}
'
获取一个搜索模板
使用get stored script API
获取一个搜索模板。
curl -X GET "localhost:9200/_scripts/my-search-template?pretty"
使用cluster state API
获取搜索模板列表和其他的脚本。
curl -X GET "localhost:9200/_cluster/state/metadata?pretty&filter_path=metadata.stored_scripts&pretty"
删除搜索模板
使用delete stored script API
删除一个搜索模板。
curl -X DELETE "localhost:9200/_scripts/my-search-template?pretty"
设置默认值
根据以下语法为变量设置默认值。
{{my-var}}{{^my-var}}default value{{/my-var}}
如果搜索模板未在其参数中指定值,则搜索将使用默认值。例如,以下模板设置了 from
和 size
的默认值。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"query": {
"match": {
"message": "{{query_string}}"
}
},
"from": "{{from}}{{^from}}0{{/from}}",
"size": "{{size}}{{^size}}10{{/size}}"
},
"params": {
"query_string": "hello world"
}
}
'
URL编码字符串
使用 {{#url}}
函数 对URL 进行字符串编码。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"query": {
"term": {
"url.full": "{{#url}}{{host}}/{{page}}{{/url}}"
}
}
},
"params": {
"host": "http://example.com",
"page": "hello-world"
}
}
'
模板呈现为:
{
"template_output": {
"query": {
"term": {
"url.full": "http%3A%2F%2Fexample.com%2Fhello-world"
}
}
}
}
连接值
使用 {{#join}}
函数将数组值连接为逗号分隔的字符串。例如,以下模板连接两个电子邮件地址。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"query": {
"match": {
"user.group.emails": "{{#join}}emails{{/join}}"
}
}
},
"params": {
"emails": [ "user1@example.com", "user_one@example.com" ]
}
}
'
模板呈现为:
{
"template_output": {
"query": {
"match": {
"user.group.emails": "user1@example.com,user_one@example.com"
}
}
}
}
您还可以指定自定义分隔符。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": {
"query": {
"range": {
"user.effective.date": {
"gte": "{{date.min}}",
"lte": "{{date.max}}",
"format": "{{#join delimiter=\u0027||\u0027}}date.formats{{/join delimiter=\u0027||\u0027}}"
}
}
}
},
"params": {
"date": {
"min": "2098",
"max": "06/05/2099",
"formats": ["dd/MM/yyyy", "yyyy"]
}
}
}
'
模板呈现为:
{
"template_output": {
"query": {
"range": {
"user.effective.date": {
"gte": "2098",
"lte": "06/05/2099",
"format": "dd/MM/yyyy||yyyy"
}
}
}
}
转换JSON
使用 {{#toJson}}
函数将变量值转换为其 JSON 表示。
例如,以下模板使用 {{#toJson}} 传递数组。为确保请求正文是有效的 JSON,source
以字符串格式编写。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": "{ \"query\": { \"terms\": { \"tags\": {{#toJson}}tags{{/toJson}} }}}",
"params": {
"tags": [
"prod",
"es01"
]
}
}
'
模板呈现为:
{
"template_output": {
"query": {
"terms": {
"tags": [
"prod",
"es01"
]
}
}
}
}
您还可以使用 {{#toJson}}
来传递对象。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": "{ \"query\": {{#toJson}}my_query{{/toJson}} }",
"params": {
"my_query": {
"match_all": { }
}
}
}
'
模板呈现为:
{
"template_output" : {
"query" : {
"match_all" : { }
}
}
}
您还可以传递对象数组。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": "{ \"query\": { \"bool\": { \"must\": {{#toJson}}clauses{{/toJson}} }}}",
"params": {
"clauses": [
{
"term": {
"user.id": "kimchy"
}
},
{
"term": {
"url.domain": "example.com"
}
}
]
}
}
'
模板呈现为:
{
"template_output": {
"query": {
"bool": {
"must": [
{
"term": {
"user.id": "kimchy"
}
},
{
"term": {
"url.domain": "example.com"
}
}
]
}
}
}
}
使用条件
要创建 if
条件,请使用以下语法:
{{#condition}}content{{/condition}}
如果条件变量为真,Elasticsearch 会显示其内容。例如,如果 year_scope
为真,以下模板将搜索过去一年的数据。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": "{ \"query\": { \"bool\": { \"filter\": [ {{#year_scope}} { \"range\": { \"@timestamp\": { \"gte\": \"now-1y/d\", \"lt\": \"now/d\" } } }, {{/year_scope}} { \"term\": { \"user.id\": \"{{user_id}}\" }}]}}}",
"params": {
"year_scope": true,
"user_id": "kimchy"
}
}
'
模板呈现为:
{
"template_output" : {
"query" : {
"bool" : {
"filter" : [
{
"range" : {
"@timestamp" : {
"gte" : "now-1y/d",
"lt" : "now/d"
}
}
},
{
"term" : {
"user.id" : "kimchy"
}
}
]
}
}
}
}
如果 year_scope
为 false
,则模板搜索任何时间段的数据。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": "{ \"query\": { \"bool\": { \"filter\": [ {{#year_scope}} { \"range\": { \"@timestamp\": { \"gte\": \"now-1y/d\", \"lt\": \"now/d\" } } }, {{/year_scope}} { \"term\": { \"user.id\": \"{{user_id}}\" }}]}}}",
"params": {
"year_scope": false,
"user_id": "kimchy"
}
}
'
模板呈现为:
{
"template_output" : {
"query" : {
"bool" : {
"filter" : [
{
"term" : {
"user.id" : "kimchy"
}
}
]
}
}
}
}
要创建 if-else
条件,请使用以下语法:
{{#condition}}if content{{/condition}} {{^condition}}else content{{/condition}}
例如,如果 year_scope 为真,以下模板将搜索过去一年的数据。否则,它将搜索过去一天的数据。
curl -X POST "localhost:9200/_render/template?pretty" -H 'Content-Type: application/json' -d'
{
"source": "{ \"query\": { \"bool\": { \"filter\": [ { \"range\": { \"@timestamp\": { \"gte\": {{#year_scope}} \"now-1y/d\" {{/year_scope}} {{^year_scope}} \"now-1d/d\" {{/year_scope}} , \"lt\": \"now/d\" }}}, { \"term\": { \"user.id\": \"{{user_id}}\" }}]}}}",
"params": {
"year_scope": true,
"user_id": "kimchy"
}
}
'