《Elasticsearch 检索》系列,共包含以下文章:
😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!!
检索模板(Search Template)
1.什么是检索模板
Elasticsearch 检索模板(Search Template)是一种预定义的搜索查询模板,使用 Mustache
模板语言编写。它允许你将查询逻辑与参数分离,使搜索查询更加动态和可重用。
2.应用场景和优势
2.1 应用场景
- 标准化查询:为团队提供统一的查询结构。
- 参数化搜索:允许用户输入不同参数获取不同结果。
- 复杂查询简化:隐藏复杂查询逻辑,提供简单接口。
- 权限控制:限制用户可以执行的查询类型。
2.2 优势
- 安全性:避免暴露查询逻辑细节。
- 可维护性:集中管理查询,一处修改多处生效。
- 灵活性:支持动态参数注入。
- 性能优化:预编译模板提高执行效率。
3.实际案例
3.1 准备测试数据
创建 products
索引并添加数据。
PUT products
{
"mappings": {
"properties": {
"name": {"type": "text"},
"price": {"type": "integer"},
"category": {"type": "keyword"},
"on_sale": {"type": "boolean"}
}
}
}
POST _bulk
{"index":{"_index":"products","_id":1}}
{"name":"华为手机 P40","price":3999,"category":"电子产品","on_sale":true}
{"index":{"_index":"products","_id":2}}
{"name":"小米手机 10","price":2999,"category":"电子产品","on_sale":false}
{"index":{"_index":"products","_id":3}}
{"name":"苹果手机 iPhone 12","price":5999,"category":"电子产品","on_sale":true}
{"index":{"_index":"products","_id":4}}
{"name":"联想笔记本电脑","price":4599,"category":"电子产品","on_sale":false}
{"index":{"_index":"products","_id":5}}
{"name":"耐克运动鞋","price":899,"category":"服装鞋帽","on_sale":true}
{"index":{"_index":"products","_id":6}}
{"name":"手机支架","price":59,"category":"配件","on_sale":true}
创建 blog
和 news
索引并添加数据。
PUT blog
{
"mappings": {
"properties": {
"title": {"type": "text"},
"content": {"type": "text"},
"created_at": {"type": "date"}
}
}
}
PUT news
{
"mappings": {
"properties": {
"title": {"type": "text"},
"content": {"type": "text"},
"created_at": {"type": "date"}
}
}
}
POST _bulk
{"index":{"_index":"blog","_id":1}}
{"title":"Elasticsearch 入门指南","content":"本文介绍Elasticsearch的基本概念和使用方法","created_at":"2023-01-15"}
{"index":{"_index":"blog","_id":2}}
{"title":"Kibana 可视化教程","content":"学习如何使用Kibana创建Elasticsearch数据的可视化","created_at":"2023-02-20"}
{"index":{"_index":"news","_id":1}}
{"title":"Elasticsearch 8.0 发布","content":"Elastic公司发布了Elasticsearch 8.0版本,带来多项新特性","created_at":"2023-03-10"}
{"index":{"_index":"news","_id":2}}
{"title":"大数据技术趋势","content":"分析2023年大数据领域的技术趋势,包括Elasticsearch的应用","created_at":"2023-04-05"}
3.2 案例 1:基础检索模板
POST _scripts/product_search_template
{
"script": {
"lang": "mustache",
"source": {
"query": {
"bool": {
"must": [
{"match": {"name": "{{query_string}}"} },
{"range": {"price": {"gte": "{{min_price}}", "lte": "{{max_price}}"}}}
]
}
},
"size": "{{size}}"
}
}
}
这段代码创建了一个名为 product_search_template
的 Elasticsearch 检索模板,其核心功能是:
动态搜索商品,支持以下参数化条件:
- 按名称模糊匹配(
query_string
参数) - 按价格范围过滤(
min_price
和max_price
参数) - 控制返回结果数量(
size
参数)
本质:将固定查询逻辑模板化,后续只需传递不同参数(如搜索关键词、价格区间)即可复用该查询结构,避免重复编写复杂 DSL。
典型应用场景:电商商品列表页的筛选查询(如搜索 “手机
” 且价格在 2000~3000 元之间的商品)。
执行模板:
GET products/_search/template
{
"id": "product_search_template",
"params": {
"query_string": "手机",
"min_price": 2000,
"max_price": 3000,
"size": 10
}
}
3.3 案例 2:带条件的模板
POST _scripts/conditional_search_template
{
"script": {
"lang": "mustache",
"source": {
"query": {
"bool": {
"must": [
{
"{{#is_on_sale}}": {
"term": {"on_sale": true}
}
},
{"match": {"category": "{{category}}"}}
]
}
}
}
}
}
这段代码定义了一个名为 conditional_search_template
的 Elasticsearch 动态检索模板,其核心特点是:
条件化商品搜索,包含以下逻辑:
- 可选条件:根据参数
is_on_sale
决定是否筛选「促销商品」(on_sale=true
) - 必选条件:固定匹配指定分类(
category
参数)
典型场景:如仅查询「电子产品」分类中参与促销的商品。
执行模板:
GET products/_search/template
{
"id": "conditional_search_template",
"params": {
"is_on_sale": true,
"category": "电子产品"
}
}
为什么原始模板会失败?
- 语法错误:Mustache 的条件语句
{{#param}}
不能直接作为 JSON 键名使用。- 结构问题:Elasticsearch 查询 DSL 必须是有效的 JSON,而原始模板在解析时破坏了 JSON 结构。
- 模板解析顺序:Mustache 先于 JSON 解析执行,导致语法冲突。
正确方式应包裹整个查询块,而非作为 JSON 键名。
3.3.1 方案 1:使用 JSON 转义
POST _scripts/conditional_search_template_v2
{
"script": {
"lang": "mustache",
"source": {
"query": {
"bool": {
"must": [
"{{#is_on_sale}}",
{"term": {"on_sale": true}},
"{{/is_on_sale}}",
{"match": {"category": "{{category}}"}}
]
}
}
}
}
}
GET products/_search/template
{
"id": "conditional_search_template_v2",
"params": {
"is_on_sale": true,
"category": "电子产品"
}
}
注意:
- 需要 Elasticsearch
7.12+
版本支持。 - 可能对复杂模板不友好。
3.3.2 方案 2:将整个模板作为字符串传递(推荐)
POST _scripts/conditional_search_template_v3
{
"script": {
"lang": "mustache",
"source": """{
"query": {
"bool": {
"must": [
{{#is_on_sale}}
{"term": {"on_sale": true}},
{{/is_on_sale}}
{"match": {"category": "{{category}}"}}
]
}
}
}"""
}
}
GET products/_search/template
{
"id": "conditional_search_template_v3",
"params": {
"is_on_sale": true,
"category": "电子产品"
}
}
关键点:
- 使用 三引号
"""
包裹整个模板内容。 - 保持模板内的 Mustache 语法不变。
- 这是 Elasticsearch 官方推荐的方式。
3.4 案例 3:多索引搜索模板
POST _scripts/multi_index_search_template
{
"script": {
"lang": "mustache",
"source": {
"query": {
"multi_match": {
"query": "{{query}}",
"fields": ["title^2", "content"]
}
},
"_source": ["title", "created_at"],
"highlight": {
"fields": {
"content": {}
}
}
}
}
}
这段代码定义了一个名为 multi_index_search_template
的 Elasticsearch 检索模板,核心功能是:
跨索引全文检索,主要特性包括:
- 多字段搜索:在
title
(权重加倍)和content
字段中匹配用户输入的关键词(query
参数)。 - 结果优化:
- 只返回
title
和created_at
字段(_source
过滤)。 - 对匹配内容高亮显示(
highlight
聚焦content
字段)。
- 只返回
典型场景:
- 同时搜索博客(
blog
)和新闻(news
)索引(需在调用时指定索引)。 - 适用于站内统一搜索引擎,如输入「Elasticsearch」同时显示相关文章标题和摘要片段。
执行模板:
GET blog,news/_search/template
{
"id": "multi_index_search_template",
"params": {
"query": "Elasticsearch"
}
}
3.5 模板管理
删除模板:
DELETE _scripts/template_name
查看所有模板:
GET _cluster/state/metadata?filter_path=metadata.stored_scripts*
检索模板是 Elasticsearch 中强大的功能,特别适合构建搜索 API 或需要频繁执行类似但参数不同的查询场景。通过模板可以保持查询一致性,同时提供必要的灵活性。
4.{#param}} 和 {{/param}}
在 Mustache 模板语言中,{{#param}}
和 {{/param}}
是一对 条件块标签,用于控制模板内容的渲染逻辑。它们的具体含义如下:
4.1 {{#param}} 的含义
- 开始条件块:表示一个条件判断的开始
- 行为取决于参数类型:
- 当
param
是布尔值 true
或非空列表
→ 渲染块内内容 - 当
param
是false
/空列表
/null
/undefined
→ 跳过块内内容 - 当
param
是对象
→ 进入当前对象的上下文(可以访问对象属性)
- 当
4.2 {{/param}} 的含义
- 结束条件块:表示条件判断的结束。
- 必须与
{{#param}}
成对出现:就像 HTML 的闭合标签。
4.3 关键注意事项
- 必须严格闭合:每个
{{#param}}
必须有对应的{{/param}}
。 - JSON 有效性:
- 条件块内的内容需要保持合法的 JSON 结构。
- 可能需要处理尾随逗号问题。
- 参数传递:
GET _search/template { "id": "my_template", "params": { "on_sale": true, // 布尔值 "tags": ["a","b"], // 数组 "price_range": { // 对象 "min": 100, "max": 500 } } }
4.4 为什么 Elasticsearch 使用这种语法?
- 逻辑与表现分离:模板只关注 “是否渲染”,不包含复杂逻辑。
- 安全性:防止代码注入(比拼接字符串更安全)。
- 跨语言兼容:Mustache 是多种语言支持的模板标准。
这种设计使得模板既灵活又可维护,特别适合作为搜索 API 的抽象层。