# Search 模板/Multi Search 模板

## Search Template / Search 模板

**\_search/template endpoint** 允许我们在执行搜索请求和使用模板参数填充现有模板之前，能够使用 **mustache**语言预先呈现搜索请求。

```
GET /_search/template
{
    "inline" : {
      "query": { "match" : { "{{my_field}}" : "{{my_value}}" } },
      "size" : "{{my_size}}"
    },
    "params" : {
        "my_field" : "foo",
        "my_value" : "bar",
        "my_size" : 5
    }
}
```

关于**Mustache templating**以及你可以使用哪种模板，请参考[mustache 项目在线文档](http://mustache.github.io/mustache.5.html)。

**NOTE:**

在**elasticsearch**中实现的**mustache**语言是作为一种沙箱(**sandboxed**) 脚本语言，因此它遵守相关设置，这些设置可能是为了启用或禁用脚本文档 ([scripting docs](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/modules-scripting-security.html#enable-dynamic-scripting))中描述的每个语言、源和操作。

### 更多的模板案例

#### 使用单个值填充查询字符串

```
GET /_search/template
{
    "inline": {
        "query": {
            "match": {
                "title": "{{query_string}}"
            }
        }
    },
    "params": {
        "query_string": "search for these words"
    }
}
```

#### 将参数转换为JSON

&#x20;**{{#toJson}}parameter{{/toJson}}** 函数可以用来转换参数（比如 maps 和 array）为它们的 JSON 形式。

```
GET /_search/template
{
  "inline": "{ \"query\": { \"terms\": { \"status\": {{#toJson}}status{{/toJson}} }}}",
  "params": {
    "status": [ "pending", "published" ]
  }
}
```

其呈现为：

```
{
  "query": {
    "terms": {
      "status": [
        "pending",
        "published"
      ]
    }
  }
}
```

更复杂的例子代替一个**JSON**对象数组：

```
{
    "inline": "{\"query\":{\"bool\":{\"must\": {{#toJson}}clauses{{\\/toJson}} }}}",
    "params": {
        "clauses": [
            { "term": "foo" },
            { "term": "bar" }
        ]
   }
}
```

呈现为：

```
{
    "query" : {
      "bool" : {
        "must" : [
          {
            "term" : "foo"
          },
          {
            "term" : "bar"
          }
        ]
      }
    }
}
```

#### 连接值的数组

{{#join}}array{{/join}}函数能用来将数组的值连接为以逗号分隔的字符串

```
GET /_search/template
{
  "inline": {
    "query": {
      "match": {
        "emails": "{{#join}}emails{{/join}}"
      }
    }
  },
  "params": {
    "emails": [ "username@email.com", "lastname@email.com" ]
  }
}
```

其呈现为：

```
{
    "query" : {
        "match" : {
            "emails" : "username@email.com,lastname@email.com"
        }
    }
}
```

该函数还可以接受一个自定义分隔符：

```
GET /_search/template
{
  "inline": {
    "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"]
    }
  }
}
```

呈现为：

```
{
    "query" : {
      "range" : {
        "born" : {
          "gte" : "2016",
          "lte" : "31/12/2017",
          "format" : "dd/MM/yyyy||yyyy"
        }
      }
    }
}
```

#### 默认值

默认值被写&#x6210;**{{var}}{{^var}}default{{/var}}**&#x6BD4;如：

```
{
  "inline": {
    "query": {
      "range": {
        "line_no": {
          "gte": "{{start}}",
          "lte": "{{end}}{{^end}}20{{/end}}"
        }
      }
    }
  },
  "params": { ... }
}
```

此时**params**&#x662F;**{ "start": 10, "end": 15 }**，该查询可以呈现为：

```
{
    "range": {
        "line_no": {
            "gte": "10",
            "lte": "15"
        }
  }
}
```

但是，当**params**&#x662F;**{ "start": 10 }**&#x65F6;， 该查询就会使用默认值作为**end**:

```
{
    "range": {
        "line_no": {
            "gte": "10",
            "lte": "20"
        }
    }
}
```

#### 条件语句

条件语句不能使用模板的**JSON**形式表示。相反，模板必须作为字符串传递。例如，假设我们想在**line**字段上运行**match**查询，并且可以选择用行号过滤其中**start**和**end**是可选的。

参数（params）会像这样：

```
{
    "params": {
        "text":      "words to search for",
        "line_no": { ①
            "start": 10, ②
            "end":   20  ③
        }
    }
}
```

| ① | 所有这三个元素都是可选的。 |
| - | ------------- |
| ② |               |
| ③ |               |

查询语句我们可以是：

```
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "line": "{{text}}" ①
        }
      },
      "filter": {
        {{#line_no}} ②
          "range": {
            "line_no": {
              {{#start}} ③
                "gte": "{{start}}" ④
                {{#end}},{{/end}} ⑤
              {{/start}} ⑥
              {{#end}} ⑦
                "lte": "{{end}}" ⑧
              {{/end}} ⑨
            }
          }
        {{/line_no}} ⑩
      }
    }
  }
}
```

① 填充**text**参数值。

② 仅当指定**line\_no** 时才能包含**range**过滤器。

③ 仅当指定了**line\_no.start**时才能包含**gte**子句。

④ 填充**line\_no.start**参数值。

⑤ 仅当**line\_no.start**和**line\_no.end**被指定时，在**gte**子句后添加逗号。

⑦ 仅当指定**line\_no.end**时，包含**lte**子句。

⑨

⑩ 填充**line\_no.end**参数值。

> 注意
>
> 如上所述，模板不是有效的**JSON**形式，因为它包含类似 的部分标记，因此，模板应存储在文件中（参考[预注册模板](http://apache.wiki/pages/viewpage.action?pageId=4882772)一节）或者在通过**REST API**使用时，应该将其写成字符串格式，比如：

```
"inline": "{\"query\":{\"bool\":{\"must\":{\"match\":{\"line\":\"{{text}}\"}},\"filter\":{{{#line_no}}\"range\":{\"line_no\":{{{#start}}\"gte\":\"{{start}}\"{{#end}},{{/end}}{{/start}}{{#end}}\"lte\":\"{{end}}\"{{/end}}}}{{/line_no}}}}}}"
```

#### 预注册（Pre-registered）模板

你可以通过将搜索模板存储在**config/scripts**目录中，在使&#x7528;**.mustache**扩展名的文件中注册搜索模板。为了执行存储的模板，请使用**template**键下单名称来引用它：

```
GET /_search/template
{
    "file": "storedTemplate", ①
    "params": {
        "query_string": "search for these words"
    }
}
```

①**config/sripts/**&#x67E5;询模板的名称，即：

`storedTemplate.mustache`**.**

你还可以通过将搜索模板存储在集群状态中来注册搜索模板，由**REST API**来管理这些索引的模板。

```
POST /_search/template/<templatename>
{
    "template": {
        "query": {
            "match": {
                "title": "{{query_string}}"
            }
        }
    }
}
```

该模板可以通过以下方法来检查：

```
GET /_search/template/<templatename>
```

其可以呈现为：

```
{
    "template": {
        "query": {
            "match": {
                "title": "{{query_string}}"
            }
        }
    }
}
```

这个模板可以被删除：

```
DELETE /_search/template/<templatename>
```

```
GET /_search/template
{
    "id": "templateName", ①
    "params": {
        "query_string": "search for these words"
    }
}
```

① 存储&#x5728;**.scripts**索引中的查询模板的名称。

#### 验证（Validating）模板

可以在具有给定参数的响应中使用来呈现模板：

```
GET /_render/template
{
  "inline": {
    "query": {
      "terms": {
        "status": [
          "{{#status}}",
          "{{.}}",
          "{{/status}}"
        ]
      }
    }
  },
  "params": {
    "status": [ "pending", "published" ]
  }
}
```

次调用将返回呈现的模板：

```
{
  "template_output": {
    "query": {
      "terms": {
        "status": [ ①
          "pending",
          "published"
        ]
      }
    }
  }
}
```

① status 数据已使用来自 params 对象的值填充。

文件和索引模板也可以通过分别用 file 或 id 代替 inline 来呈现。例如，呈现文件模板：

```
GET /_render/template
{
  "file": "my_template",
  "params": {
    "status": [ "pending", "published" ]
  }
}
```

预注册模板可以使用以下呈现：

```
GET /_render/template/<template_name>
{
  "params": {
    "..."
  }
}
```

## Multi Search 模板

多搜索（**Multi Search**）模板**API**允许使&#x7528;**\_msearch/template**端点在同一个**API**中执行多个搜索模板请求。

以下请求形式与 多搜索**API**形式相似：

```
header\n
body\n
header\n
body\n
```

**header**部分与一般的多搜索 API 支持相同的**index**，**types**，**search\_type**，**preference**和**routing**选项。

**body**部分包含一个搜索模板**body**请求，并且支持 inline，存储和文件模板。比如：

```
$ cat requests
{"index": "test"}
{"inline": {"query": {"match":  {"user" : "{{username}}" }}}, "params": {"username": "john"}} ①
{"index": "_all", "types": "accounts"}
{"inline": {"query": {"{{query_type}}": {"name": "{{name}}" }}}, "params": {"query_type": "match_phrase_prefix", "name": "Smith"}}
{"index": "_all"}
{"id": "template_1", "params": {"query_string": "search for these words" }} ②
{"types": "users"}
{"file": "template_2", "params": {"field_name": "fullname", "field_value": "john smith" }} ③

$ curl -XGET localhost:9200/_msearch/template --data-binary "@requests"; echo
```

①inline 搜索模板请求

②基于存储模板的搜索模板请求

③基于文件模板的搜索模板请求

响应返回一个 .response 数组，其中包括每个搜索模板请求的搜索模板响应，该响应匹配其在原始多搜索模板请求中的顺序。如果该特定搜索模板请求的完全失败，将返回**error**消息的对象，而不是实际的搜索响应。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xiaoxiami.gitbook.io/elasticsearch/ji-chu/33-apis/343sou-suo-apis-search-apis/search-mo-ban.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
