2.3.1 引入查询模板
自Elasticsearch 1.1.0版本开始,我们可以自定义查询模板。让我们回到本书开头的在线书店例子中。假定我们已经确定了需要传递给Elasticsearch的查询语句的类型,不过查询结构并未最终确定,我们还需要对它进行微调和优化。通过使用查询模板,我们可以快速构建出查询的基础骨架,然后让应用程序来提供对应的参数,最终由Elasticsearch完成查询参数的替换。
假定我们有一个针对library索引的查询语句,可以返回最相关的书籍记录。在这个查询中,我们还允许用户选择是否对书籍的库存状态做筛选。在这个场景中,我们需要传入两个参数—一个查询短语和一个代表书籍库存状态的布尔变量。最初的简化示例如下:
代码中的QUERY和BOOLEAN是占位符,代表应用程序传递给查询的变量。显然这个查询语句对当前示例场景来说实在太简陋了,不过之前我们已经说过,这只是它的最初版本,我们马上将对它进行改进。
既然已经有了最初版本的查询语句,我们可以基于它创建第一个查询模板。对该查询语句做简单修改如下:
可以看出,原来的占位符被替换成了{{phrase}}和{{avail}}两个变量,并且添加了一个新的params片段。当Elasticsearch在解析查询语句时,遇到一个{{phrase}}变量,它将尝试从params片段中查找出名为phrase的参数,并用参数值替换掉{{phrase}}变量。通常,我们需要把参数值放到params片段中,并在query中使用形如{{var}}的标记来引用params片段中参数名为var的参数。此外,查询本身被嵌套进一个template元素中。通过这种方式,我们实现了查询的参数化。
接下来让我们使用HTTP GET请求把以下查询语句发送给地址为/library/_search/template的REST端点(注意这里不是我们通常使用的/library/_search端点)。请求命令构造如下:
字符串形式的查询模板
查询模板也可以以字符串的形式提供。比如,刚才的查询模板可以变成这样:
可见,这种形式不太适合阅读和书写,每个引号都需要被转义,换行符容易引发格式问题,因此需要避免使用。尽管如此,如果你需要使用Mustache(一个模板引擎,我们将在下一小节探讨),则必须使用这种格式(至少在Elasticsearch的1.1.0到1.4.0之间的所有版本中必须这样做)。
本书写作时,笔者所使用的Elasticsearch相关版本中有一个关于查询模板的小陷阱。如果你提供的查询模板中有错误,被Elasticsearch检测到后,会把错误写到服务日志里,但是从API的视角来看,错误查询将被忽略,接口将返回所有文档,就好像你刚刚发送了一个match_all查询一样。记得复查你的查询模板,直到这个缺陷不再存在。