一、search template简介
elasticsearch提供了search template功能,其会在实际执行查询之前,对search template进行预处理并将参数填充到template中。
elasticsearch主要提供了两个API来支持search template
_scripts/
_search/template使用search template进行搜索;
二、测试数据准备
批量index三个文档
POST _bulk
{ "index" : { "_index" : "search_template_test", "_type" : "_doc", "_id" : "1" } }
{ "name":"zhang san", "age":30, "man":true, "address":"Hebei LangFang"}
{ "index" : { "_index" : "search_template_test", "_type" : "_doc", "_id" : "2" } }
{ "name":"li si", "age":20, "man":true, "address":"BeiJing HaiDian"}
{ "index" : { "_index" : "search_template_test", "_type" : "_doc", "_id" : "3" } }
{ "name":"liu hui", "age":40, "man":false, "address":"NeiMengGu ChiFeng"}
查询查看三个索引的文档
GET search_template_test/_search
{
"took":6,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":3,
"max_score":1,
"hits":[
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"2",
"_score":1,
"_source":{
"name":"li si",
"age":20,
"man":true,
"address":"BeiJing HaiDian"
}
},
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"1",
"_score":1,
"_source":{
"name":"zhang san",
"age":30,
"man":true,
"address":"Hebei LangFang"
}
},
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"3",
"_score":1,
"_source":{
"name":"liu hui",
"age":40,
"man":false,
"address":"NeiMengGu ChiFeng"
}
}
]
}
}
三、维护search template
我们新建id为search_template_test.match_name的search template,其主要是查询match 字段name;
POST _scripts/search_template_test.match_name
{
"script": {
"lang": "mustache",
"source": {
"query": {
"match": {
"name": "{{name_val}}"
}
}
}
}
}
查看我们创建的search template
GET _scripts/search_template_test.match_name
{
"_id":"search_template_test.match_name",
"found":true,
"script":{
"lang":"mustache",
"source":"{\"query\":{\"match\":{\"name\":\"{{name_val}}\"}}}",
"options":{
"content_type":"application/json; charset=UTF-8"
}
}
}
删除我们创建的search template
DELET _scripts/search_template_test.match_name
{
"acknowledged":true
}
elasticsearch提供了API支持我们查看预处理最终形成的查询语句;
POST _render/template/search_template_test.match_name
{
"params":{
"name_val":"zhang li"
}
}
{
"template_output":{
"query":{
"match":{
"name":"zhang li"
}
}
}
}
四、使用search template
我们可以像下边这样使用search template
POST search_template_test/_search/template
{
"id": "search_template_test.match_name",
"params": {
"name_val":"zhang li"
}
}
{
"took":1,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":2,
"max_score":0.2876821,
"hits":[
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"2",
"_score":0.2876821,
"_source":{
"name":"li si",
"age":20,
"man":true,
"address":"BeiJing HaiDian"
}
},
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"1",
"_score":0.2876821,
"_source":{
"name":"zhang san",
"age":30,
"man":true,
"address":"Hebei LangFang"
}
}
]
}
}
执行search template也支持使用explain来调试查看elasticsearch的打分情况;
POST search_template_test/_search/template
{
"id": "search_template_test.match_name",
"params": {
"name_val":"zhang li"
},
"explain":true
}
{
"took":3,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":2,
"max_score":0.2876821,
"hits":[
{
"_shard":"[search_template_test][2]",
"_node":"Sl6S4Kn2Rh-BdNgaM3ZwJg",
"_index":"search_template_test",
"_type":"_doc",
"_id":"2",
"_score":0.2876821,
"_source":{
"name":"li si",
"age":20,
"man":true,
"address":"BeiJing HaiDian"
},
"_explanation":{
"value":0.2876821,
"description":"sum of:",
"details":[
{
"value":0.2876821,
"description":"weight(name:li in 0) [PerFieldSimilarity], result of:",
"details":[
......
]
}
]
}
},
{
"_shard":"[search_template_test][3]",
"_node":"Sl6S4Kn2Rh-BdNgaM3ZwJg",
"_index":"search_template_test",
"_type":"_doc",
"_id":"1",
"_score":0.2876821,
"_source":{
"name":"zhang san",
"age":30,
"man":true,
"address":"Hebei LangFang"
},
"_explanation":{
"value":0.2876821,
"description":"sum of:",
"details":[
{
"value":0.2876821,
"description":"weight(name:zhang in 0) [PerFieldSimilarity], result of:",
"details":[
......
]
}
]
}
}
]
}
}
执行search template也支持使用profile来调试查看elasticsearch的查询执行情况;
POST search_template_test/_search/template
{
"id": "search_template_test.match_name",
"params": {
"name_val":"zhang li"
},
"profile":true
}
{
"took":11,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":2,
"max_score":0.2876821,
"hits":[
]
},
"profile":{
"shards":[
{
"id":"[Sl6S4Kn2Rh-BdNgaM3ZwJg][search_template_test][0]",
"searches":[
{
"query":[
{
"type":"BooleanQuery",
"description":"name:zhang name:li",
"time_in_nanos":308301,
"breakdown":{
"score":0,
"build_scorer_count":0,
"match_count":0,
"create_weight":308300,
"next_doc":0,
"match":0,
"create_weight_count":1,
"next_doc_count":0,
"score_count":0,
"build_scorer":0,
"advance":0,
"advance_count":0
},
"children":[
{
"type":"TermQuery",
"description":"name:zhang",
"time_in_nanos":32901,
"breakdown":{
"score":0,
"build_scorer_count":0,
"match_count":0,
"create_weight":32900,
"next_doc":0,
"match":0,
"create_weight_count":1,
"next_doc_count":0,
"score_count":0,
"build_scorer":0,
"advance":0,
"advance_count":0
}
},
{
"type":"TermQuery",
"description":"name:li",
"time_in_nanos":15901,
"breakdown":{
"score":0,
"build_scorer_count":0,
"match_count":0,
"create_weight":15900,
"next_doc":0,
"match":0,
"create_weight_count":1,
"next_doc_count":0,
"score_count":0,
"build_scorer":0,
"advance":0,
"advance_count":0
}
}
]
}
],
"rewrite_time":42700,
"collector":[
{
"name":"CancellableCollector",
"reason":"search_cancelled",
"time_in_nanos":700,
"children":[
{
"name":"SimpleTopScoreDocCollector",
"reason":"search_top_hits",
"time_in_nanos":200
}
]
}
]
}
],
"aggregations":[
]
}
]
}
}
五、使用search template处理复杂的查询
我们构建以下search template,其功能如下
可以通过name字段进行match,如果命中字段中的各个关键字相邻则有更高的权重打分,同时可以通过address字段进行模糊匹配,这三个查询只要命中一个即可;
man字段值必须符合输入的值;
POST _scripts/search_template_test.multi_search_template
{
"script":{
"lang":"mustache",
"source":{
"query":{
"bool":{
"should":[
{
"match":{
"name":"{{name}}"
}
},
{
"match_phrase_prefix":{
"name":"{{name}}"
}
},
{
"query_string":{
"default_field":"address",
"query":"{{#join delimiter=' '}}address{{/join delimiter=' '}}"
}
}
],
"filter":{
"term":{
"man":"{{man}}"
}
},
"minimum_should_match":1
}
}
}
}
}
通过以下参数命中前两条数据
POST search_template_test/_search/template
{
"id":"search_template_test.multi_search_template",
"params":{
"name":"zhang sa",
"address":[
"*bei*",
"*chi*"
],
"man":true
}
}
{
"took":10,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":2,
"max_score":1.8630463,
"hits":[
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"1",
"_score":1.8630463,
"_source":{
"name":"zhang san",
"age":30,
"man":true,
"address":"Hebei LangFang"
}
},
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"2",
"_score":1,
"_source":{
"name":"li si",
"age":20,
"man":true,
"address":"BeiJing HaiDian"
}
}
]
}
}
我们将man字段设置为false,从而只匹配第三条记录;
POST search_template_test/_search/template
{
"id":"search_template_test.multi_search_template",
"params":{
"name":"zhang sa",
"address":[
"*bei*",
"*chi*"
],
"man":false
}
}
{
"took":4,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"skipped":0,
"failed":0
},
"hits":{
"total":1,
"max_score":1,
"hits":[
{
"_index":"search_template_test",
"_type":"_doc",
"_id":"3",
"_score":1,
"_source":{
"name":"liu hui",
"age":40,
"man":false,
"address":"NeiMengGu ChiFeng"
}
}
]
}
}