Solr的默认查询解析器也称为”lucene”解析器。
标准查询解析器的关键优势在于它支持强大且相当直观的语法,允许你创建各种结构化查询。最大的缺点是它对语法错误非常不宽容,与DisMax查询解析器相比,后者设计为尽可能少抛出错误。
标准查询解析器参数
除了通用查询参数、分面参数、高亮参数和更多类似查询参数外,标准查询解析器还支持下表中描述的参数。
q
定义使用标准查询语法的查询。此参数是必需的。
q.op
指定查询表达式的默认运算符。可能的值是”AND”或”OR”。
df
指定默认可搜索字段。
sow
在空白处分割。如果设置为true
,则为每个单独的空白分隔词单独调用文本分析。默认值是false
;空白分隔的词序列将一次性提供给文本分析,使得在词序列上操作的分析过滤器能够正常运行,例如多词同义词和shingles。
默认参数值在solrconfig.xml
中指定,或者在请求中通过查询时值覆盖。
标准查询解析器响应
默认情况下,标准查询解析器的响应包含一个未命名的<result>
块。如果使用了debug
参数,那么将返回一个名为”debug”的附加<lst>
块。这将包含有用的调试信息,包括原始查询字符串、解析的查询字符串,以及<result>
块中每个文档的解释信息。如果还使用了explainOther
参数,那么将为匹配该查询的所有文档提供附加的解释信息。
示例响应
本节展示了标准查询解析器响应的示例。
以下URL提交了一个简单查询,并请求XML响应编写器使用缩进来使XML响应更可读。
1 | http://localhost:8983/solr/techproducts/select?q=id:SP2514N&wt=xml |
结果:
1 | <response> |
这是一个带有限制字段列表的查询示例。
1 | http://localhost:8983/solr/techproducts/select?q=id:SP2514N&fl=id+name&wt=xml |
结果:
1 | <response> |
为标准查询解析器指定词条
对标准查询解析器的查询被分解为词条和运算符。有两种类型的词条:单词条和短语。
- 单词条是一个单词,如”test”或”hello”
- 短语是用双引号包围的一组词,如”hello dolly”
多个词条可以与布尔运算符结合形成更复杂的查询(如下所述)。
**重要:**用于查询的分析器解析词条和短语的方式与用于索引的分析器解析词条和短语的方式一致是很重要的;否则,搜索可能产生意外结果。
词条修饰符
Solr支持各种词条修饰符,根据需要为搜索添加灵活性或精确性。这些修饰符包括通配符字符、用于使搜索”模糊”或更一般的字符等。下面的部分详细描述了这些修饰符。
通配符搜索
Solr的标准查询解析器在单个词条中支持单字符和多字符通配符搜索。通配符字符可以应用于单个词条,但不能应用于搜索短语。
通配符搜索类型 | 特殊字符 | 示例 |
---|---|---|
单字符(匹配单个字符) | ? |
搜索字符串te?t 会匹配test和text |
多字符(匹配零个或多个连续字符) | * |
通配符搜索tes* 会匹配test、testing和tester。你也可以在词条中间使用通配符字符。例如:te*t 会匹配test和text。*est 会匹配pest和test |
模糊搜索
Solr的标准查询解析器支持基于Damerau-Levenshtein距离或编辑距离算法的模糊搜索。模糊搜索发现与指定词条相似的词条,而不必是完全匹配。要执行模糊搜索,在单词词条的末尾使用波浪号~符号。例如,要搜索在拼写上与”roam”相似的词条,使用模糊搜索:
1 | roam~ |
此搜索将匹配roams、foam和foams等词条。它也会匹配”roam”本身。
可选的距离参数指定允许的最大编辑次数,在0和2之间,默认为2。例如:
1 | roam~1 |
这将匹配roams和foam等词条 - 但不会匹配foams,因为它的编辑距离是”2”。
**重要:**在许多情况下,词干提取(将词条减少到共同词干)可以产生与模糊搜索和通配符搜索类似的效果。
如果需要更高级的模糊搜索选项,如prefixLength
或maxExpansions
,这些可以通过模糊查询解析器启用。
邻近搜索
邻近搜索查找彼此在特定距离内的词条。
要执行邻近搜索,在搜索短语的末尾添加波浪号字符~和数值。例如,要搜索在文档中彼此相距10个词以内的”apache”和”jakarta”,使用搜索:
1 | "jakarta apache"~10 |
这里提到的距离是匹配指定短语所需的词条移动次数。在上面的例子中,如果”apache”和”jakarta”在字段中相距10个空格,但”apache”出现在”jakarta”之前,则需要超过10次词条移动来将词条移动到一起,并将”apache”定位到”jakarta”的右边,中间有一个空格。
存在搜索
字段的存在搜索匹配该字段存在值的所有文档。要查询字段存在,只需在搜索中使用通配符而不是词条。
1 | field:* |
如果字段有任何值,甚至是通常被认为”不存在”的值(例如,NaN
、""
等),该字段将被认为”存在”。
范围搜索
范围搜索指定字段的值范围(具有上界和下界的范围)。查询匹配指定字段的值落在范围内的文档。范围查询可以包含或排除上界和下界。排序是按词典顺序进行的,除了数值字段。例如,下面的范围查询匹配所有popularity
字段值在52和10,000之间(包含)的文档。
1 | popularity:[52 TO 10000] |
范围查询不限于日期字段或甚至数值字段。你也可以对非日期字段使用范围查询:
1 | title:{Aida TO Carmen} |
这将找到所有标题在Aida和Carmen之间但不包括Aida和Carmen的文档。
查询周围的括号决定了其包含性。
- 方括号
[
和]
表示包含范围查询,匹配包括上界和下界的值 - 花括号
{
和}
表示排他范围查询,匹配上界和下界之间的值,但排除上界和下界本身 - 你可以混合这些类型,使范围的一端是包含的,另一端是排他的。这是一个例子:
count:{1 TO 10]
通配符*
也可以用于一个或两个端点来指定开放式范围查询。这与Lucene的经典查询解析器不同。
field:[* TO 100]
找到所有小于或等于100的字段值field:[100 TO *]
找到所有大于或等于100的字段值field:[* TO *]
找到在该字段类型的-Infinity和+Infinity有效值之间有值的任何文档
注意:用通配符匹配NaN值
对于大多数字段,无界范围查询field:[* TO *]
等价于存在查询field: *
。但是,对于支持NaN
值的float/double类型,这两个查询的执行是不同的。
field:*
匹配所有现有值,包括NaN
field:[* TO *]
匹配所有实数值,排除NaN
用”^”增强词条
Solr基于找到的词条提供匹配文档的相关性级别。要增强词条,在你正在搜索的词条末尾使用插入符号^
和增强因子(数字)。增强因子越高,词条越相关。
增强允许你通过增强文档的词条来控制文档的相关性。例如,如果你正在搜索”jakarta apache”并且你希望词条”jakarta”更相关,你可以通过在词条后立即添加^符号和增强因子来增强它。例如,你可以输入:
1 | jakarta^4 apache |
这将使带有词条jakarta的文档显得更相关。你也可以增强短语词条,如示例中:
1 | "jakarta apache"^4 "Apache Lucene" |
默认情况下,增强因子是1。虽然增强因子必须是正数,但它可以小于1(例如,它可以是0.2)。
用”^=”实现常量分数
常量分数查询用<query_clause>^=<score>
创建,它为匹配该子句的任何文档将整个子句设置为指定分数。当你只关心特定子句的匹配而不希望其他相关性因素(如词频(词条在字段中出现的次数)或逆文档频率(跨整个索引衡量词条在字段中有多稀有))时,这是理想的。
示例:
1 | (description:blue OR color:blue)^=1.0 text:shoes |
查询特定字段
Solr中索引的数据在字段中组织,字段在模式中定义。搜索可以利用字段为查询增加精确性。例如,你可以只在特定字段中搜索词条,如标题字段。
模式定义一个字段为默认字段。如果你在查询中没有指定字段,Solr只搜索默认字段。或者,你可以在查询中指定不同的字段或字段组合。
要指定字段,输入字段名,后跟冒号”:”,然后是你在字段中搜索的词条。
例如,假设索引包含两个字段,title和text,并且text是默认字段。如果你想找到一个名为”The Right Way”的文档,其中包含文本”don’t go this way”,你可以在搜索查询中包含以下任一词条:
1 | title:"The Right Way" AND text:go |
1 | title:"Do it right" AND go |
由于text是默认字段,不需要字段指示符;因此上面的第二个查询省略了它。
字段只对它直接前面的词条有效,所以查询title:Do it right
只会在标题字段中找到”Do”。它会在默认字段(在这种情况下是text字段)中找到”it”和”right”。
标准查询解析器支持的布尔运算符
布尔运算符允许你对查询应用布尔逻辑,要求特定词条或条件在字段中存在或不存在以匹配文档。下表总结了标准查询解析器支持的布尔运算符。
布尔运算符 | 替代符号 | 描述 |
---|---|---|
AND | && |
要求布尔运算符两边的词条都存在才能匹配 |
NOT | ! |
要求以下词条不存在 |
OR | ` | |
+ | + |
要求以下词条存在 |
- | - |
禁止以下词条(即,匹配不包含该词条的字段或文档)。- 运算符在功能上类似于布尔运算符! 。因为它被Google等流行搜索引擎使用,对某些用户社区来说可能更熟悉 |
布尔运算符允许通过逻辑运算符组合词条。Lucene支持AND、”+”、OR、NOT和”-“作为布尔运算符。
**重要:**当使用如AND或NOT等关键字指定布尔运算符时,关键字必须以全大写形式出现。
**注意:**标准查询解析器支持上表中列出的所有布尔运算符。DisMax查询解析器只支持+
和-
。
OR运算符是默认连接运算符。这意味着如果两个词条之间没有布尔运算符,则使用OR运算符。OR运算符连接两个词条,如果任一词条在文档中存在,则找到匹配文档。这等价于使用集合的并集。符号||可以代替单词OR使用。
要搜索包含”jakarta apache”或只包含”jakarta”的文档,使用查询:
1 | "jakarta apache" jakarta |
或
1 | "jakarta apache" OR jakarta |
布尔运算符”+”
+
符号(也称为”必需”运算符)要求+
符号后的词条在至少一个文档的字段中某处存在,查询才能返回匹配。
例如,要搜索必须包含”jakarta”且可能包含或不包含”lucene”的文档,使用以下查询:
1 | +jakarta lucene |
**注意:**这个运算符被标准查询解析器和DisMax查询解析器都支持。
布尔运算符AND(”&&”)
AND运算符匹配两个词条在单个文档文本中任何地方都存在的文档。这等价于使用集合的交集。符号&&
可以代替单词AND使用。
要搜索包含”jakarta apache”和”Apache Lucene”的文档,使用以下任一查询:
1 | "jakarta apache" AND "Apache Lucene" |
1 | "jakarta apache" && "Apache Lucene" |
布尔运算符NOT(”!”)
NOT运算符排除包含NOT后词条的文档。这等价于使用集合的差集。符号!
可以代替单词NOT使用。
以下查询搜索包含短语”jakarta apache”但不包含短语”Apache Lucene”的文档:
1 | "jakarta apache" NOT "Apache Lucene" |
1 | "jakarta apache" ! "Apache Lucene" |
布尔运算符”-“
-
符号或”禁止”运算符排除包含-
符号后词条的文档。
例如,要搜索包含”jakarta apache”但不包含”Apache Lucene”的文档,使用以下查询:
1 | "jakarta apache" -"Apache Lucene" |
转义特殊字符
当以下字符出现在查询中时,Solr赋予它们特殊含义:
1 | + - && || ! ( ) { } [ ] ^ " ~ * ? : / |
要让Solr将这些字符中的任何一个解释为字面意思,而不是特殊字符,在字符前加一个反斜杠字符\
。例如,要搜索(1+1):2而不让Solr将加号和括号解释为用于制定有两个词条的子查询的特殊字符,通过在每个前面加反斜杠来转义字符:
1 | \(1\+1\)\:2 |
分组词条形成子查询
Solr支持使用括号来分组子句以形成子查询。如果你想控制查询的布尔逻辑,这可能非常有用。
下面的查询搜索”jakarta”或”apache”和”website”:
1 | (jakarta OR apache) AND website |
这为查询增加了精确性,要求词条”website”存在,以及词条”jakarta”和”apache”中的任一个。
在字段内分组子句
要对搜索中单个字段应用两个或多个布尔运算符,在括号内分组布尔子句。例如,下面的查询搜索包含单词”return”和短语”pink panther”的标题字段:
1 | title:(+return +"pink panther") |
查询中的注释
查询字符串中支持C风格注释。
示例:
1 | "jakarta apache" /* this is a comment in the middle of a normal query string */ OR jakarta |
注释可以嵌套。
Lucene经典查询解析器与Solr标准查询解析器的差异
Solr的标准查询解析器起源于Lucene”经典”QueryParser的变体。它在以下方面有所不同:
*
可以用于一个或两个端点来指定开放式范围查询,或者单独作为存在查询field:[* TO 100]
找到所有小于或等于100的字段值field:[100 TO *]
找到所有大于或等于100的字段值field:[* TO *]
找到字段值在-Infinity
和Infinity
之间的所有文档,排除NaN
field:*
找到字段存在(即有任何值)的所有文档
允许纯负查询(所有子句被禁止)(仅作为顶级子句)
-inStock:false
找到inStock不为false的所有字段值-field:*
找到该字段没有值的所有文档
支持使用本地参数语法将任何类型的查询解析器作为嵌套子句的嵌入Solr查询(子查询)
inStock:true OR {!dismax qf='name manu' v='ipod'}
**注意:**小心不要在查询的最开头以{!
开始,这会改变整个查询字符串的解析,如果有附加子句,这可能不是你想要的。所以如果将上面的例子翻转使子查询首先出现,没有前导空格将无法按预期工作。
子查询也可以用魔法字段_query_
来完成,对于函数查询可以用魔法字段_val_
,但由于不太清楚,应该被认为已弃用。示例:_val_:"recip(rord(myfield),1,2,3)"
- 支持特殊的
filter(...)
语法来指示某些查询子句应该缓存在过滤器缓存中(作为常量分数布尔查询)。这允许子查询被缓存并在其他查询中重用。例如inStock:true
将被缓存并在以下三个查询中重用:q=features:songs OR filter(inStock:true)
q=+manu:Apple +filter(inStock:true)
q=+manu:Apple & fq=inStock:true
这甚至可以用于缓存复杂过滤查询的各个子句。在下面的第一个查询中,3个项目将被添加到过滤器缓存(顶级fq
和两个filter(...)
子句),在第二个查询中,将有2个缓存命中和一个新的缓存插入(用于新的顶级fq
):
q=features:songs & fq=+filter(inStock:true) +filter(price:[* TO 100])
q=manu:Apple & fq=-filter(inStock:true) -filter(price:[* TO 100])
范围查询(”[a TO z]”)、前缀查询(”a*”)和通配符查询(”a*b”)是常量评分的(所有匹配文档得到相等分数)。不使用评分因子TF、IDF、索引增强和”coord”。匹配词条数量没有限制(在Lucene的过去版本中有限制)。
常量分数查询用
<query_clause>^=<score>
创建,它为匹配该子句的任何文档将整个子句设置为指定分数:q=(description:blue color:blue)^=1.0 title:blue^=5.0
指定日期和时间
对基于日期的字段的查询必须使用适当的日期格式化。对确切日期值的查询将需要引号或转义,因为:
是用于表示字段查询的解析器语法:
createdate:1976-03-06T23\:59\:59.999Z
createdate:"1976-03-06T23:59:59.999Z"
createdate:[1976-03-06T23:59:59.999Z TO *]
createdate:[1995-12-31T23:59:59.999Z TO 2007-03-06T00:00:00Z]
timestamp:[* TO NOW]
pubdate:[NOW-1YEAR/DAY TO NOW/DAY+1DAY]
createdate:[1976-03-06T23:59:59.999Z TO 1976-03-06T23:59:59.999Z+1YEAR]
createdate:[1976-03-06T23:59:59.999Z/YEAR TO 1976-03-06T23:59:59.999Z]
总结
标准查询解析器是Solr最强大的查询工具,提供了丰富的语法支持,包括布尔运算符、范围查询、通配符搜索、模糊搜索等功能。虽然它对语法错误较为严格,但其强大的表达能力使其成为复杂查询场景的首选。理解和掌握标准查询解析器的语法和特性,对于构建高效的Solr搜索应用至关重要。