New

The executive guide to generative AI

Read more

搜索模板

编辑

搜索模板是一种存储的搜索,您可以使用不同的变量来运行它。

如果您使用 Elasticsearch 作为搜索后端,您可以将搜索栏中的用户输入作为搜索模板的参数传递。这使您可以在不向用户公开 Elasticsearch 的查询语法的情况下运行搜索。

如果您将 Elasticsearch 用于自定义应用程序,搜索模板允许您更改搜索,而无需修改应用程序的代码。

创建搜索模板

编辑

要创建或更新搜索模板,请使用 创建存储的脚本 API

请求的 source 支持与 搜索 API 的请求正文相同的参数。source 还接受来自开源项目 mustache.javaMustache 变量。

通常,Mustache 变量包含在双花括号中:{{my-var}}。当您运行模板化搜索时,Elasticsearch 会将这些变量替换为 params 中的值。要了解有关 mustache 语法的更多信息,请参阅 Mustache.js 手册。搜索模板必须使用 mustachelang

以下请求创建一个 idmy-search-template 的搜索模板。

resp = client.put_script(
    id="my-search-template",
    script={
        "lang": "mustache",
        "source": {
            "query": {
                "match": {
                    "message": "{{query_string}}"
                }
            },
            "from": "{{from}}",
            "size": "{{size}}"
        }
    },
)
print(resp)
response = client.put_script(
  id: 'my-search-template',
  body: {
    script: {
      lang: 'mustache',
      source: {
        query: {
          match: {
            message: '{{query_string}}'
          }
        },
        from: '{{from}}',
        size: '{{size}}'
      }
    }
  }
)
puts response
const response = await client.putScript({
  id: "my-search-template",
  script: {
    lang: "mustache",
    source: {
      query: {
        match: {
          message: "{{query_string}}",
        },
      },
      from: "{{from}}",
      size: "{{size}}",
    },
  },
});
console.log(response);
PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source": {
      "query": {
        "match": {
          "message": "{{query_string}}"
        }
      },
      "from": "{{from}}",
      "size": "{{size}}"
    }
  }
}

Elasticsearch 将搜索模板作为 Mustache 脚本存储在集群状态中。Elasticsearch 在 template 脚本上下文中编译搜索模板。限制或禁用脚本的设置也会影响搜索模板。

验证搜索模板

编辑

要使用不同的 params 测试模板,请使用 渲染搜索模板 API

resp = client.render_search_template(
    id="my-search-template",
    params={
        "query_string": "hello world",
        "from": 20,
        "size": 10
    },
)
print(resp)
response = client.render_search_template(
  body: {
    id: 'my-search-template',
    params: {
      query_string: 'hello world',
      from: 20,
      size: 10
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  id: "my-search-template",
  params: {
    query_string: "hello world",
    from: 20,
    size: 10,
  },
});
console.log(response);
POST _render/template
{
  "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 来测试内联模板。

resp = client.render_search_template(
    source={
        "query": {
            "match": {
                "message": "{{query_string}}"
            }
        },
        "from": "{{from}}",
        "size": "{{size}}"
    },
    params={
        "query_string": "hello world",
        "from": 20,
        "size": 10
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: {
      query: {
        match: {
          message: '{{query_string}}'
        }
      },
      from: '{{from}}',
      size: '{{size}}'
    },
    params: {
      query_string: 'hello world',
      from: 20,
      size: 10
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: {
    query: {
      match: {
        message: "{{query_string}}",
      },
    },
    from: "{{from}}",
    size: "{{size}}",
  },
  params: {
    query_string: "hello world",
    from: 20,
    size: 10,
  },
});
console.log(response);
POST _render/template
{
    "source": {
      "query": {
        "match": {
          "message": "{{query_string}}"
        }
      },
      "from": "{{from}}",
      "size": "{{size}}"
    },
  "params": {
    "query_string": "hello world",
    "from": 20,
    "size": 10
  }
}

运行模板化搜索

编辑

要使用搜索模板运行搜索,请使用 搜索模板 API。您可以在每个请求中指定不同的 params

resp = client.search_template(
    index="my-index",
    id="my-search-template",
    params={
        "query_string": "hello world",
        "from": 0,
        "size": 10
    },
)
print(resp)
response = client.search_template(
  index: 'my-index',
  body: {
    id: 'my-search-template',
    params: {
      query_string: 'hello world',
      from: 0,
      size: 10
    }
  }
)
puts response
const response = await client.searchTemplate({
  index: "my-index",
  id: "my-search-template",
  params: {
    query_string: "hello world",
    from: 0,
    size: 10,
  },
});
console.log(response);
GET my-index/_search/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "hello world",
    "from": 0,
    "size": 10
  }
}

响应使用与 搜索 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",
        "_id": "1",
        "_score": 0.5753642,
        "_source": {
          "message": "hello world"
        }
      }
    ]
  }
}

运行多个模板化搜索

编辑

要使用单个请求运行多个模板化搜索,请使用 多搜索模板 API。与多个单独的搜索相比,这些请求通常具有更少的开销和更快的速度。

resp = client.msearch_template(
    index="my-index",
    search_templates=[
        {},
        {
            "id": "my-search-template",
            "params": {
                "query_string": "hello world",
                "from": 0,
                "size": 10
            }
        },
        {},
        {
            "id": "my-other-search-template",
            "params": {
                "query_type": "match_all"
            }
        }
    ],
)
print(resp)
response = client.msearch_template(
  index: 'my-index',
  body: [
    {},
    {
      id: 'my-search-template',
      params: {
        query_string: 'hello world',
        from: 0,
        size: 10
      }
    },
    {},
    {
      id: 'my-other-search-template',
      params: {
        query_type: 'match_all'
      }
    }
  ]
)
puts response
const response = await client.msearchTemplate({
  index: "my-index",
  search_templates: [
    {},
    {
      id: "my-search-template",
      params: {
        query_string: "hello world",
        from: 0,
        size: 10,
      },
    },
    {},
    {
      id: "my-other-search-template",
      params: {
        query_type: "match_all",
      },
    },
  ],
});
console.log(response);
GET my-index/_msearch/template
{ }
{ "id": "my-search-template", "params": { "query_string": "hello world", "from": 0, "size": 10 }}
{ }
{ "id": "my-other-search-template", "params": { "query_type": "match_all" }}

获取搜索模板

编辑

要检索搜索模板,请使用 获取存储的脚本 API

resp = client.get_script(
    id="my-search-template",
)
print(resp)
response = client.get_script(
  id: 'my-search-template'
)
puts response
const response = await client.getScript({
  id: "my-search-template",
});
console.log(response);
GET _scripts/my-search-template

要获取所有搜索模板和其他存储的脚本的列表,请使用 集群状态 API

resp = client.cluster.state(
    metric="metadata",
    pretty=True,
    filter_path="metadata.stored_scripts",
)
print(resp)
response = client.cluster.state(
  metric: 'metadata',
  pretty: true,
  filter_path: 'metadata.stored_scripts'
)
puts response
const response = await client.cluster.state({
  metric: "metadata",
  pretty: "true",
  filter_path: "metadata.stored_scripts",
});
console.log(response);
GET _cluster/state/metadata?pretty&filter_path=metadata.stored_scripts

删除搜索模板

编辑

要删除搜索模板,请使用 删除存储的脚本 API

resp = client.delete_script(
    id="my-search-template",
)
print(resp)
response = client.delete_script(
  id: 'my-search-template'
)
puts response
const response = await client.deleteScript({
  id: "my-search-template",
});
console.log(response);
DELETE _scripts/my-search-template

设置默认值

编辑

要为变量设置默认值,请使用以下语法

{{my-var}}{{^my-var}}default value{{/my-var}}

如果模板化搜索未在其 params 中指定值,则搜索将使用默认值。例如,以下模板为 fromsize 设置默认值。

resp = client.render_search_template(
    source={
        "query": {
            "match": {
                "message": "{{query_string}}"
            }
        },
        "from": "{{from}}{{^from}}0{{/from}}",
        "size": "{{size}}{{^size}}10{{/size}}"
    },
    params={
        "query_string": "hello world"
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: {
      query: {
        match: {
          message: '{{query_string}}'
        }
      },
      from: '{{from}}{{^from}}0{{/from}}',
      size: '{{size}}{{^size}}10{{/size}}'
    },
    params: {
      query_string: 'hello world'
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: {
    query: {
      match: {
        message: "{{query_string}}",
      },
    },
    from: "{{from}}{{^from}}0{{/from}}",
    size: "{{size}}{{^size}}10{{/size}}",
  },
  params: {
    query_string: "hello world",
  },
});
console.log(response);
POST _render/template
{
  "source": {
    "query": {
      "match": {
        "message": "{{query_string}}"
      }
    },
    "from": "{{from}}{{^from}}0{{/from}}",
    "size": "{{size}}{{^size}}10{{/size}}"
  },
  "params": {
    "query_string": "hello world"
  }
}

URL 编码字符串

编辑

使用 {{#url}} 函数对字符串进行 URL 编码。

resp = client.render_search_template(
    source={
        "query": {
            "term": {
                "url.full": "{{#url}}{{host}}/{{page}}{{/url}}"
            }
        }
    },
    params={
        "host": "http://example.com",
        "page": "hello-world"
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: {
      query: {
        term: {
          'url.full' => '{{#url}}{{host}}/{{page}}{{/url}}'
        }
      }
    },
    params: {
      host: 'http://example.com',
      page: 'hello-world'
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: {
    query: {
      term: {
        "url.full": "{{#url}}{{host}}/{{page}}{{/url}}",
      },
    },
  },
  params: {
    host: "http://example.com",
    page: "hello-world",
  },
});
console.log(response);
POST _render/template
{
  "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}} 函数将数组值连接为逗号分隔的字符串。例如,以下模板连接两个电子邮件地址。

resp = client.render_search_template(
    source={
        "query": {
            "match": {
                "user.group.emails": "{{#join}}emails{{/join}}"
            }
        }
    },
    params={
        "emails": [
            "user1@example.com",
            "user_one@example.com"
        ]
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: {
      query: {
        match: {
          'user.group.emails' => '{{#join}}emails{{/join}}'
        }
      }
    },
    params: {
      emails: [
        'user1@example.com',
        'user_one@example.com'
      ]
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: {
    query: {
      match: {
        "user.group.emails": "{{#join}}emails{{/join}}",
      },
    },
  },
  params: {
    emails: ["user1@example.com", "user_one@example.com"],
  },
});
console.log(response);
POST _render/template
{
  "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"
      }
    }
  }
}

您还可以指定自定义分隔符。

resp = client.render_search_template(
    source={
        "query": {
            "range": {
                "user.effective.date": {
                    "gte": "{{date.min}}",
                    "lte": "{{date.max}}",
                    "format": "{{#join delimiter='||'}}date.formats{{/join delimiter='||'}}"
                }
            }
        }
    },
    params={
        "date": {
            "min": "2098",
            "max": "06/05/2099",
            "formats": [
                "dd/MM/yyyy",
                "yyyy"
            ]
        }
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: {
      query: {
        range: {
          'user.effective.date' => {
            gte: '{{date.min}}',
            lte: '{{date.max}}',
            format: "{{#join delimiter='||'}}date.formats{{/join delimiter='||'}}"
          }
        }
      }
    },
    params: {
      date: {
        min: '2098',
        max: '06/05/2099',
        formats: [
          'dd/MM/yyyy',
          'yyyy'
        ]
      }
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: {
    query: {
      range: {
        "user.effective.date": {
          gte: "{{date.min}}",
          lte: "{{date.max}}",
          format:
            "{{#join delimiter='||'}}date.formats{{/join delimiter='||'}}",
        },
      },
    },
  },
  params: {
    date: {
      min: "2098",
      max: "06/05/2099",
      formats: ["dd/MM/yyyy", "yyyy"],
    },
  },
});
console.log(response);
POST _render/template
{
  "source": {
    "query": {
      "range": {
        "user.effective.date": {
          "gte": "{{date.min}}",
          "lte": "{{date.max}}",
          "format": "{{#join delimiter='||'}}date.formats{{/join delimiter='||'}}"
	      }
      }
    }
  },
  "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 以字符串格式编写。

resp = client.render_search_template(
    source="{ \"query\": { \"terms\": { \"tags\": {{#toJson}}tags{{/toJson}} }}}",
    params={
        "tags": [
            "prod",
            "es01"
        ]
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: '{ "query": { "terms": { "tags": {{#toJson}}tags{{/toJson}} }}}',
    params: {
      tags: [
        'prod',
        'es01'
      ]
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: '{ "query": { "terms": { "tags": {{#toJson}}tags{{/toJson}} }}}',
  params: {
    tags: ["prod", "es01"],
  },
});
console.log(response);
POST _render/template
{
  "source": "{ \"query\": { \"terms\": { \"tags\": {{#toJson}}tags{{/toJson}} }}}",
  "params": {
    "tags": [
      "prod",
      "es01"
    ]
  }
}

模板渲染为

{
  "template_output": {
    "query": {
      "terms": {
        "tags": [
          "prod",
          "es01"
        ]
      }
    }
  }
}

您还可以使用 {{#toJson}} 传递对象。

resp = client.render_search_template(
    source="{ \"query\": {{#toJson}}my_query{{/toJson}} }",
    params={
        "my_query": {
            "match_all": {}
        }
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: '{ "query": {{#toJson}}my_query{{/toJson}} }',
    params: {
      my_query: {
        match_all: {}
      }
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: '{ "query": {{#toJson}}my_query{{/toJson}} }',
  params: {
    my_query: {
      match_all: {},
    },
  },
});
console.log(response);
POST _render/template
{
  "source": "{ \"query\": {{#toJson}}my_query{{/toJson}} }",
  "params": {
    "my_query": {
      "match_all": { }
    }
  }
}

模板渲染为

{
  "template_output" : {
    "query" : {
      "match_all" : { }
    }
  }
}

您还可以传递对象数组。

resp = client.render_search_template(
    source="{ \"query\": { \"bool\": { \"must\": {{#toJson}}clauses{{/toJson}} }}}",
    params={
        "clauses": [
            {
                "term": {
                    "user.id": "kimchy"
                }
            },
            {
                "term": {
                    "url.domain": "example.com"
                }
            }
        ]
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: '{ "query": { "bool": { "must": {{#toJson}}clauses{{/toJson}} }}}',
    params: {
      clauses: [
        {
          term: {
            'user.id' => 'kimchy'
          }
        },
        {
          term: {
            'url.domain' => 'example.com'
          }
        }
      ]
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: '{ "query": { "bool": { "must": {{#toJson}}clauses{{/toJson}} }}}',
  params: {
    clauses: [
      {
        term: {
          "user.id": "kimchy",
        },
      },
      {
        term: {
          "url.domain": "example.com",
        },
      },
    ],
  },
});
console.log(response);
POST _render/template
{
  "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}}

如果条件变量为 true,则 Elasticsearch 会显示其内容。例如,如果 year_scopetrue,则以下模板会搜索过去一年的数据。

resp = client.render_search_template(
    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"
    },
)
print(resp)
response = client.render_search_template(
  body: {
    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'
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  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",
  },
});
console.log(response);
POST _render/template
{
  "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_scopefalse,则模板会搜索任何时间段的数据。

resp = client.render_search_template(
    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"
    },
)
print(resp)
response = client.render_search_template(
  body: {
    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'
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  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",
  },
});
console.log(response);
POST _render/template
{
  "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_scopetrue,则以下模板会搜索过去一年的数据。否则,它会搜索过去一天的数据。

resp = client.render_search_template(
    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"
    },
)
print(resp)
response = client.render_search_template(
  body: {
    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'
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  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",
  },
});
console.log(response);
POST _render/template
{
  "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"
  }
}

带有 Mustache 的搜索模板示例

编辑

mustache 模板语言定义了您可以在模板中使用的各种标记类型。以下各节描述了其中一些标记类型,并提供了在 Elasticsearch 搜索模板中使用它们的示例。

Mustache 变量

编辑

Mustache 标记通常包含在双花括号中。Mustache 变量:{{my-variable}} 是一种 Mustache 标记。当您运行模板化搜索时,Elasticsearch 会将这些变量替换为 params 中的值。

例如,考虑以下搜索模板

resp = client.put_script(
    id="my-search-template",
    script={
        "lang": "mustache",
        "source": {
            "query": {
                "match": {
                    "message": "{{query_string}}"
                }
            },
            "from": "{{from}}",
            "size": "{{size}}"
        }
    },
)
print(resp)
response = client.put_script(
  id: 'my-search-template',
  body: {
    script: {
      lang: 'mustache',
      source: {
        query: {
          match: {
            message: '{{query_string}}'
          }
        },
        from: '{{from}}',
        size: '{{size}}'
      }
    }
  }
)
puts response
const response = await client.putScript({
  id: "my-search-template",
  script: {
    lang: "mustache",
    source: {
      query: {
        match: {
          message: "{{query_string}}",
        },
      },
      from: "{{from}}",
      size: "{{size}}",
    },
  },
});
console.log(response);
PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source": {
      "query": {
        "match": {
          "message": "{{query_string}}"
        }
      },
      "from": "{{from}}",
      "size": "{{size}}"
    }
  }
}

使用 params 测试上述搜索模板

resp = client.render_search_template(
    id="my-search-template",
    params={
        "query_string": "hello world",
        "from": 20,
        "size": 10
    },
)
print(resp)
response = client.render_search_template(
  body: {
    id: 'my-search-template',
    params: {
      query_string: 'hello world',
      from: 20,
      size: 10
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  id: "my-search-template",
  params: {
    query_string: "hello world",
    from: 20,
    size: 10,
  },
});
console.log(response);
POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "hello world",
    "from": 20,
    "size": 10
  }
}

渲染后,message 中的 {{query_string}} 将被 params 中传递的 hello world 替换。

{
  "template_output": {
    "query": {
      "match": {
        "message": "hello world"
      }
    },
    "from": "20",
    "size": "10"
  }
}

如果您的搜索模板没有将值传递给您的 query_string,则消息将被替换为空字符串。

例如

resp = client.render_search_template(
    id="my-search-template",
    params={
        "from": 20,
        "size": 10
    },
)
print(resp)
response = client.render_search_template(
  body: {
    id: 'my-search-template',
    params: {
      from: 20,
      size: 10
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  id: "my-search-template",
  params: {
    from: 20,
    size: 10,
  },
});
console.log(response);
POST _render/template
{
  "id": "my-search-template",
  "params": {
    "from": 20,
    "size": 10
  }
}

渲染后,模板输出为

{
  "template_output": {
    "query": {
      "match": {
        "message": ""
      }
    },
    "from": "20",
    "size": "10"
  }
}

节也是一种 Mustache 标记。您可以在搜索模板中使用带有嵌套或非嵌套对象的 sections。节以 {{#my-section-variable}} 开头,以 {{/my-section-variable}} 结尾。

以下搜索模板显示了使用带有嵌套对象的节的示例

resp = client.render_search_template(
    source="\n  {\n    \"query\": {\n      \"match\": {\n        {{#query_message}}\n          {{#query_string}}\n        \"message\": \"Hello {{#first_name_section}}{{first_name}}{{/first_name_section}} {{#last_name_section}}{{last_name}}{{/last_name_section}}\"\n          {{/query_string}}\n        {{/query_message}}\n      }\n    }\n  }\n  ",
    params={
        "query_message": {
            "query_string": {
                "first_name_section": {
                    "first_name": "John"
                },
                "last_name_section": {
                    "last_name": "kimchy"
                }
            }
        }
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: "\n  {\n    \"query\": {\n      \"match\": {\n        {{#query_message}}\n          {{#query_string}}\n        \"message\": \"Hello {{#first_name_section}}{{first_name}}{{/first_name_section}} {{#last_name_section}}{{last_name}}{{/last_name_section}}\"\n          {{/query_string}}\n        {{/query_message}}\n      }\n    }\n  }\n  ",
    params: {
      query_message: {
        query_string: {
          first_name_section: {
            first_name: 'John'
          },
          last_name_section: {
            last_name: 'kimchy'
          }
        }
      }
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source:
    '\n  {\n    "query": {\n      "match": {\n        {{#query_message}}\n          {{#query_string}}\n        "message": "Hello {{#first_name_section}}{{first_name}}{{/first_name_section}} {{#last_name_section}}{{last_name}}{{/last_name_section}}"\n          {{/query_string}}\n        {{/query_message}}\n      }\n    }\n  }\n  ',
  params: {
    query_message: {
      query_string: {
        first_name_section: {
          first_name: "John",
        },
        last_name_section: {
          last_name: "kimchy",
        },
      },
    },
  },
});
console.log(response);
POST _render/template
{
  "source":
  """
  {
    "query": {
      "match": {
        {{#query_message}}
          {{#query_string}}
        "message": "Hello {{#first_name_section}}{{first_name}}{{/first_name_section}} {{#last_name_section}}{{last_name}}{{/last_name_section}}"
          {{/query_string}}
        {{/query_message}}
      }
    }
  }
  """,
  "params": {
    "query_message": {
       "query_string": {
         "first_name_section": {"first_name": "John"},
         "last_name_section": {"last_name": "kimchy"}
       }
    }
  }
}

模板渲染为

{
  "template_output": {
    "query": {
      "match": {
        "message": "Hello John kimchy"
      }
    }
  }
}

列表

编辑

您可以传递对象列表,并在搜索模板中循环访问每个项目。

例如,以下搜索模板结合了 并匹配所有用户名

resp = client.put_script(
    id="my-search-template",
    script={
        "lang": "mustache",
        "source": {
            "query": {
                "multi_match": {
                    "query": "{{query_string}}",
                    "fields": "[{{#text_fields}}{{user_name}},{{/text_fields}}]"
                }
            }
        }
    },
)
print(resp)
response = client.put_script(
  id: 'my-search-template',
  body: {
    script: {
      lang: 'mustache',
      source: {
        query: {
          multi_match: {
            query: '{{query_string}}',
            fields: '[{{#text_fields}}{{user_name}},{{/text_fields}}]'
          }
        }
      }
    }
  }
)
puts response
const response = await client.putScript({
  id: "my-search-template",
  script: {
    lang: "mustache",
    source: {
      query: {
        multi_match: {
          query: "{{query_string}}",
          fields: "[{{#text_fields}}{{user_name}},{{/text_fields}}]",
        },
      },
    },
  },
});
console.log(response);
PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source": {
      "query":{
        "multi_match":{
          "query": "{{query_string}}",
          "fields": """[{{#text_fields}}{{user_name}},{{/text_fields}}]"""
        }
      }
    }
  }
}

测试模板

resp = client.render_search_template(
    id="my-search-template",
    params={
        "query_string": "My string",
        "text_fields": [
            {
                "user_name": "John"
            },
            {
                "user_name": "kimchy"
            }
        ]
    },
)
print(resp)
response = client.render_search_template(
  body: {
    id: 'my-search-template',
    params: {
      query_string: 'My string',
      text_fields: [
        {
          user_name: 'John'
        },
        {
          user_name: 'kimchy'
        }
      ]
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  id: "my-search-template",
  params: {
    query_string: "My string",
    text_fields: [
      {
        user_name: "John",
      },
      {
        user_name: "kimchy",
      },
    ],
  },
});
console.log(response);
POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "My string",
    "text_fields": [
      {
        "user_name": "John"
      },
      {
        "user_name": "kimchy"
      }
    ]
  }
}

渲染后,模板输出

{
  "template_output": {
    "query": {
      "multi_match": {
        "query": "My string",
        "fields": "[John,kimchy,]"
      }
    }
  }
}

以上将导致尾随逗号问题,从而导致无效的 JSON。一种解决方法是包含一个 倒置节 并添加一个变量,以确保它是数组中的最后一个项目。

例如

resp = client.put_script(
    id="my-search-template",
    script={
        "lang": "mustache",
        "source": {
            "query": {
                "multi_match": {
                    "query": "{{query_string}}",
                    "fields": "[{{#text_fields}}{{user_name}}{{^last}},{{/last}}{{/text_fields}}]"
                }
            }
        }
    },
)
print(resp)
response = client.put_script(
  id: 'my-search-template',
  body: {
    script: {
      lang: 'mustache',
      source: {
        query: {
          multi_match: {
            query: '{{query_string}}',
            fields: '[{{#text_fields}}{{user_name}}{{^last}},{{/last}}{{/text_fields}}]'
          }
        }
      }
    }
  }
)
puts response
const response = await client.putScript({
  id: "my-search-template",
  script: {
    lang: "mustache",
    source: {
      query: {
        multi_match: {
          query: "{{query_string}}",
          fields:
            "[{{#text_fields}}{{user_name}}{{^last}},{{/last}}{{/text_fields}}]",
        },
      },
    },
  },
});
console.log(response);
PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source": {
      "query":{
        "multi_match":{
          "query": "{{query_string}}",
          "fields": """[{{#text_fields}}{{user_name}}{{^last}},{{/last}}{{/text_fields}}]"""
        }
      }
    }
  }
}

再次使用变量:last 测试 my-search-template,以确定它是数组中的最后一个项目

resp = client.render_search_template(
    id="my-search-template",
    params={
        "query_string": "My string",
        "text_fields": [
            {
                "user_name": "John",
                "last": False
            },
            {
                "user_name": "kimchy",
                "last": True
            }
        ]
    },
)
print(resp)
response = client.render_search_template(
  body: {
    id: 'my-search-template',
    params: {
      query_string: 'My string',
      text_fields: [
        {
          user_name: 'John',
          last: false
        },
        {
          user_name: 'kimchy',
          last: true
        }
      ]
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  id: "my-search-template",
  params: {
    query_string: "My string",
    text_fields: [
      {
        user_name: "John",
        last: false,
      },
      {
        user_name: "kimchy",
        last: true,
      },
    ],
  },
});
console.log(response);
POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "My string",
    "text_fields": [
      {
        "user_name": "John",
        "last": false
      },
      {
        "user_name": "kimchy",
        "last": true
      }
    ]
  }
}

渲染后,模板输出

{
  "template_output": {
    "query": {
      "multi_match": {
        "query": "My string",
        "fields": "[John,kimchy]"
      }
    }
  }
}

Lambda

编辑

Elasticsearch 具有预构建的自定义函数,以支持将文本转换为特定格式。

要了解有关使用 mustache lambda 的更多信息,请查看 Url 编码字符串连接值转换为 json 中的示例。

倒置节

编辑

当您只想设置一次值时,倒置节非常有用。

要使用倒置节,请使用以下语法

{{^my-variable}} content {{/my-variable}}

例如,在以下搜索模板中,如果 name_existsfalse,则 message 设置为 Hello World,否则将其设置为空字符串。

resp = client.render_search_template(
    source={
        "query": {
            "match": {
                "message": "{{^name_exists}}Hello World{{/name_exists}}"
            }
        }
    },
    params={
        "name_exists": False
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: {
      query: {
        match: {
          message: '{{^name_exists}}Hello World{{/name_exists}}'
        }
      }
    },
    params: {
      name_exists: false
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: {
    query: {
      match: {
        message: "{{^name_exists}}Hello World{{/name_exists}}",
      },
    },
  },
  params: {
    name_exists: false,
  },
});
console.log(response);
POST _render/template
{
  "source": {
    "query": {
      "match": {
        "message": "{{^name_exists}}Hello World{{/name_exists}}"
      }
    }
  },
  "params": {
     "name_exists": false
  }
}

它们还可以与 条件默认值 结合使用。

例如,在以下搜索模板中,如果 name_existstrue,则替换 {{query_string}} 的值。如果 name_existsfalse,则将其设置为默认值 World

resp = client.render_search_template(
    source={
        "query": {
            "match": {
                "message": "Hello {{#name_exists}}{{query_string}}{{/name_exists}}{{^name_exists}}World{{/name_exists}}"
            }
        }
    },
    params={
        "query_string": "Kimchy",
        "name_exists": True
    },
)
print(resp)
response = client.render_search_template(
  body: {
    source: {
      query: {
        match: {
          message: 'Hello {{#name_exists}}{{query_string}}{{/name_exists}}{{^name_exists}}World{{/name_exists}}'
        }
      }
    },
    params: {
      query_string: 'Kimchy',
      name_exists: true
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  source: {
    query: {
      match: {
        message:
          "Hello {{#name_exists}}{{query_string}}{{/name_exists}}{{^name_exists}}World{{/name_exists}}",
      },
    },
  },
  params: {
    query_string: "Kimchy",
    name_exists: true,
  },
});
console.log(response);
POST _render/template
{
  "source": {
    "query": {
      "match": {
        "message": "Hello {{#name_exists}}{{query_string}}{{/name_exists}}{{^name_exists}}World{{/name_exists}}"
      }
    }
  },
  "params": {
    "query_string": "Kimchy",
     "name_exists": true
  }
}

渲染后,模板输出

{
  "template_output": {
    "query": {
      "match": {
        "message": "Hello Kimchy"
      }
    }
  }
}

设置分隔符

编辑

您可以将默认分隔符:双花括号 {{my-variable}} 更改为搜索模板中的任何自定义分隔符。

例如,以下搜索模板将默认分隔符更改为单个圆括号 (query_string)

resp = client.put_script(
    id="my-search-template",
    script={
        "lang": "mustache",
        "source": "\n    {\n      \"query\": {\n        \"match\": {\n           {{=( )=}}\n          \"message\": \"(query_string)\"\n          (={{ }}=)\n        }\n      }\n    }\n    "
    },
)
print(resp)
response = client.put_script(
  id: 'my-search-template',
  body: {
    script: {
      lang: 'mustache',
      source: "\n    {\n      \"query\": {\n        \"match\": {\n           {{=( )=}}\n          \"message\": \"(query_string)\"\n          (={{ }}=)\n        }\n      }\n    }\n    "
    }
  }
)
puts response
const response = await client.putScript({
  id: "my-search-template",
  script: {
    lang: "mustache",
    source:
      '\n    {\n      "query": {\n        "match": {\n           {{=( )=}}\n          "message": "(query_string)"\n          (={{ }}=)\n        }\n      }\n    }\n    ',
  },
});
console.log(response);
PUT _scripts/my-search-template
{
  "script": {
    "lang": "mustache",
    "source":
    """
    {
      "query": {
        "match": {
           {{=( )=}}
          "message": "(query_string)"
          (={{ }}=)
        }
      }
    }
    """
  }
}

使用新的分隔符测试模板

resp = client.render_search_template(
    id="my-search-template",
    params={
        "query_string": "hello world"
    },
)
print(resp)
response = client.render_search_template(
  body: {
    id: 'my-search-template',
    params: {
      query_string: 'hello world'
    }
  }
)
puts response
const response = await client.renderSearchTemplate({
  id: "my-search-template",
  params: {
    query_string: "hello world",
  },
});
console.log(response);
POST _render/template
{
  "id": "my-search-template",
  "params": {
    "query_string": "hello world"
  }
}

渲染后,模板输出

{
  "template_output": {
    "query": {
      "match": {
        "message": "hello world"
      }
    }
  }
}

不支持的功能

编辑

以下 mustache 功能在 Elasticsearch 搜索模板中不受支持

  • 局部
Was this helpful?
Feedback