3.8 Elasticsearch-搜索模板 & Mustache 动态渲染
3.8.1 为什么需要搜索模板
在实际业务里,同一条 DSL 往往要在多个场景复用:
- Web、App、小程序三端检索同一批商品,只是排序字段不同;
- BI 报表每天凌晨跑批,查询条件里的时间窗口由调度系统动态传入;
- 对外开放 API,不允许调用方拼接 DSL,防止字段名或 range 条件被恶意篡改。
搜索模板(Search Template)把“查询骨架”和“业务参数”彻底解耦:骨架存到集群里,调用方只传参数,既减少网络传输,也做到“一次编写,多处复用”。
3.8.2 模板引擎 Mustache 简介
Elasticsearch 内置的是Mustache——Logic-less 模板语言,语法只有 3 个核心符号:
{{var}}占位符,直接替换;{{#section}} … {{/section}}布尔/列表区块,真或循环才展开;{{^inverted}} … {{/inverted}}反向区块,假才展开。
Mustache 没有 if、else、>、< 等运算符,所有逻辑由调用方提前算好,再塞进 params,从根本上杜绝“脚本注入”风险。
3.8.3 模板的 CURD
- 新建/覆盖
POST_scripts/sku_search{"script":{"lang":"mustache","source":{"query":{"bool":{"filter":[{"term":{"category":"{{cat}}"}},{"range":{"price":{"gte":"{{min}}","lte":"{{max}}"}}}],"must":[{"match":{"title":{"query":"{{kw}}","boost":2}}}]}},"sort":[{"{{sort_field}}":{"order":"{{sort_order}}"}}],"from":"{{from}}","size":"{{size}}"}}}- 查看
GET_scripts/sku_search- 删除
DELETE_scripts/sku_search3.8.4 带参调用与渲染预览
正式搜索:
GETshop/_search/template{"id":"sku_search","params":{"cat":"手机","min":0,"max":5000,"kw":"5G 全网通","sort_field":"sold","sort_order":"desc","from":0,"size":20}}调试阶段想看 DSL 长什么样,用_render/template即可:
POST_render/template/sku_search{"params":{"cat":"电脑","min":3000,"max":8000,"kw":"轻薄本",...}}返回体里的template_output就是最终发给引擎的 JSON,方便在 Kibana 里二次验证。
3.8.5 高级语法速查
| 场景 | 示例 | 渲染后 |
|---|---|---|
| 原样输出 JSON | "filter": {{#toJson}}status_list{{/toJson}} | "filter": ["paid","shipped"] |
| 数组循环 | "{{#fields}}\"{{.}}\"{{^last}},{{/last}}{{/fields}}" | "title","price","sold" |
| 缺省值 | "{{default_size}}{{^default_size}}10{{/default_size}}" | 10 |
| 反向节 | "{{^vip}}\"sort\":[{\"_score\":\"desc\"}]{{/vip}}" | 非会员才按相关度排序 |
注意:
- 所有变量名大小写敏感;
- 脚本最大 10 240 字符,Serverless 实例默认单应用最多 10 条,可调配额;
- 不允许在 Mustache 里再嵌套其他脚本,防止逃逸。
3.8.6 与业务代码集成的最佳实践
版本化命名
order_search_v1、order_search_v2,灰度时并行存在,回滚秒级切换。参数白名单
网关层先做 JSON-Schema 校验,拒绝多余字段,再透传 ES,避免“字段炸弹”。热更新
CI 流水线把模板 PUT 进集群,随后发业务包;不回滚代码即可回滚模板。压测模板
先用_render把 100 组随机参数渲染成真实 DSL,再丢进 Rally,防止模板写得过于复杂导致集群抖动。
3.8.7 小结
搜索模板 + Mustache 让 Elasticsearch 的查询从“硬编码”走向“配置化”。
- 对开发:DSL 一次编写,三端复用;
- 对运维:版本可控,灰度无忧;
- 对安全:调用方只能改参数,不能改结构。
在对外 API、多租户 SaaS、实时报表等场景,先把模板当作“第一等公民”去设计,能显著降低后期维护与扩容成本。
更多技术文章见公众号: 大城市小农民