Mastering Elasticsearch(中文版)

Lucene查询语言


ElasticSearch提供的一些查询方式(query types)能够被Lucene的查询解析器(query parser)语法所支持。由于这个原因,我们来深入学习Lucene查询语言,了解其庐山真面目吧。

基础语法

用户使用Lucene进行查询操作时,输入的查询语句会被分解成一个或者多个Term以及逻辑运算符号。一个Term,在Lucene中可以是一个词,也可以是一个短语(用双引号括引来的多个词)。如果事先设定规则:解析查询语句,那么指定的analyzer就会用来处理查询语句的每个term形成Query对象。


一个Query对象中会存在多个布尔运算符,这些布尔运算符将多个Term关联起来形成查询子句。布尔运算符号有如下类型:


  • AND(与):给定两个Term(左运算对象和右运算对象),形成一个查询表达式。只有两个Term都匹配成功,查询子句才匹配成功。比如:查询语句"apache AND lucene"的意思是匹配含apache且含lucene的文档。
  • OR(或):给定的多个Term,只要其中一个匹配成功,其形成的查询表达式就匹配成功。比如查询表达式"apache OR lucene"能够匹配包含“apache”的文档,也能匹配包含"lucene"的文档,还能匹配同时包含这两个Term的文档。
  • NOT(非): 这意味着对于与查询语句匹配的文档,NOT运算符后面的Term就不能在文档中出现的。例如:查询表达式“lucene NOT elasticsearch”就只能匹配包含lucene但是不含elasticsearch的文档。

此外,我们也许会用到如下的运算符:
  • +这个符号表明:如果想要查询语句与文档匹配,那么给定的Term必须出现在文档中。例如:希望搜索到包含关键词lucene,最好能包含关键词apache的文档,可以用如下的查询表达式:"+lucene apache"。
  • -这个符号表明:如果想要查询语句与文档匹配,那么给定的Term不能出现在文档中。例如:希望搜索到包含关键词lucene,但是不含关键词elasticsearch的文档,可以用如下的查询表达式:"+lucene -elasticsearch"。
如果在Term前没有指定运算符,那么默认使用OR运算符。
此外,也是最后一点:查询表达式可以用小括号组合起来,形成复杂的查询表达式。比如:
elasticsearch AND (mastering OR book)

多域查询

当然,跟ElasticSearch一样,Lucene中的所有数据都是存储在一个个的Field中,多个Field形成一个Document。如果希望查询指定的Field,就需要在查询表达式中指定Field Name(此域名非彼域名),后面接一个冒号,紧接着一个查询表达式。例如:查询title域中包含关键词elasticsearch的文档,查询表达式如下:

title:elasticsearch
也可以把多个查询表达式用于一个域中。例如:查询title域中含关键词elasticsearch并且含短语“mastering book”的文档,查询表达式如下:
title:(+elasticsearch +"mastering book")
当然,也可以换一种写法,作用是一样的:
+title:elasticsearch +title:"mastering book")

词语修饰符

除了可以应用简单的关键词和查询表达式实现标准的域查询,Lucene还支持往查询表达式中传入修饰符使关键词具有变形能力。最常用的修饰符,也是大家都熟知的,就是通配符。Lucene支持?和\*两种通配符。?可以匹配任意单个字符,而\*能够匹配多个字符。

请注意出于性能考虑,默认的通配符不能是关键词的首字母。

此外,Lucene支持模糊查询(fuzzy query)和邻近查询(proximity query)。语法规则是查询表达式后面接一个~符号,后面紧跟一个整数。如果查询表达式是单独一个Term,这表示我们的搜索关键词可以由Term变形(替换一个字符,添加一个字符,删除一个字符)而来,即与Term是相似的。这种搜索方式称为模糊搜索(fuzzy search)。在~符号后面的整数表示最大编辑距离。例如:执行查询表达式 "writer~2"能够搜索到含writer和writers的文档。

当~符号用于一个短语时,~后面的整数表示短语中可接收的最大的词编辑距离(短语中替换一个词,添加一个词,删除一个词)。举个例子,查询表达式title:"mastering elasticsearch"只能匹配title域中含"mastering elasticsearch"的文档,而无法匹配含"mastering book elasticsearch"的文档。但是如果查询表达式变成title:"mastering elasticsearch"~2,那么两种文档就都能够成功匹配了。


此外,我们还可以使用加权(boosting)机制来改变关键词的重要程度。加权机制的语法是一个^符号后面接一个浮点数表示权重。如果权重小于1,就会降低关键词的重要程度。同理,如果权重大于1就会增加关键词的重要程度。默认的加权值为1。可以参考 第2章 活用用户查询语言  Lucene默认打分规则详解 章节部分的内容来了解更多关于加权(boosting)是如何影响打分排序的。

除了上述的功能外,Lucene还支持区间查询(range searching),其语法是用中括号或者}表示区间。例如:如果我们查询一个数值域(numeric field),可以用如下查询表达式:

price:[10.00 TO 15.00]

这条查询表达式能查询到price域的值在10.00到15.00之间的所有文档。

对于string类型的field,区间查询也同样适用。例如:

name:[Adam TO Adria]

这条查询表达式能查询到name域中含关键词Adam到关键词Adria之间关键词(字符串升序,且闭区间)的文档。

如果希望区间的边界值不会被搜索到,那么就需要用大括号替换原来的中括号。例如,查询price域中价格在10.00(10.00要能够被搜索到)到15.00(15.00不能被搜索到)之间的文档,就需要用如下的查询表达式:

price:[10.00 TO 15.00}

处理特殊字符

如果在搜索关键词中出现了如下字符集合中的任意一个字符,就需要用反斜杠(\\)进行转义。字符集合如下: +, -, &&, || , ! , (,) , { } , [ ] , ^, " , ~, *, ?, : , \, / 。例如,查询关键词 abc"efg 就需要转义成 abc\"efg。