【Elasticsearch】检索模板(Search Template)
《Elasticsearch 检索》系列,共包含以下文章:
- 精准匹配检索(Exact Match)
- 全文检索 & 组合检索
- 检索高亮
- 检索排序 & 分页
- 深度分页及其替代方案
- 自定义评分检索
- 检索模板(Search Template)
😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!!
检索模板(Search Template)
- 1.什么是检索模板
- 2.应用场景和优势
- 2.1 应用场景
- 2.2 优势
- 3.实际案例
- 3.1 准备测试数据
- 3.2 案例 1:基础检索模板
- 3.3 案例 2:带条件的模板
- 3.3.1 方案 1:使用 JSON 转义
- 3.3.2 方案 2:将整个模板作为字符串传递(推荐)
- 3.4 案例 3:多索引搜索模板
- 3.5 模板管理
- 4.{#param}} 和 {{/param}}
- 4.1 {{#param}} 的含义
- 4.2 {{/param}} 的含义
- 4.3 关键注意事项
- 4.4 为什么 Elasticsearch 使用这种语法?
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 的抽象层。