天天看點

Solr布爾查詢的使用實踐

前言

Solr支援布爾查詢,使用AND、OR、&&、!、+、-符号,具體可參考社群的

文檔介紹

但是,在使用過程中,可能有些查詢的結果會引起困擾,需要深入了解Lucene的boolean查詢規則。本文就拿具體的例子介紹如何了解其中的規則。

規則

布爾查詢在代碼中主要有下面四種辨別,BooleanClause.java。

  • MUST,用

    +

    辨別
  • SHOULD,用

    空字元

  • MUST_NOT,用

    -

  • FILTER(不常用,先忽略)

結果按照下面規則傳回。

1.MUST和MUST:取得連個查詢子句的交集。

2.MUST和MUST_NOT:表示查詢結果中不能包含MUST_NOT所對應得查詢子句的檢索結果。

3.SHOULD與MUST_NOT:連用時,功能同MUST和MUST_NOT。

4.SHOULD與MUST連用時,結果為MUST子句的檢索結果,但是SHOULD可影響排序。

5.SHOULD與SHOULD:表示“或”關系,最終檢索結果為所有檢索子句的并集。

6.MUST_NOT和MUST_NOT:無意義,檢索無結果。

在使用布爾查詢時,最容易引起誤解的是

-

文法,是以,下面的例子主要講述

-

的使用。其它文法的使用和普通的布爾邏輯語義類似。

舉例

在使用Solr查詢時,如何确定布爾查詢的符号,可以通過debugQeury擷取到parsedquery_toString。

寫入四條資料:

id,update_version_l,name_s,age_i

1,1,zhangsan,10

2,2,lisi,10

3,3,wangwu,20

4,4,zhaoliu,10

Solr布爾查詢的使用實踐
  • 示例1
age_i:10 OR -name_s:zhangsan   
#找到age_i等于10的資料,或者name_s不等于zhangsan的資料。按照正常布爾邏輯的了解,應該傳回4條資料,但實際查詢隻傳回2條資料           
Solr布爾查詢的使用實踐

編譯後的文法是

age_i:[10 TO 10] -name_s:zhangsan           

代表的是

SHOULD和MUST_NOT的組合

,參照規則3。

序号 查詢條件 命中的id
1 age_i:[10 TO 10] 1,2,4
2 name_s:zhangsan

按照規則3:首先拿到序号1條件的結果,再排除序号2條件的結果,也就是最終結果為2, 4。

  • 示例2
age_i:10 OR (-name_s:zhangsan)
#業務要達到的目的和示例1一緻,期望傳回4條資料,但實際結果傳回3條資料。           
Solr布爾查詢的使用實踐

編譯後的文法

age_i:[10 TO 10](-name_s:zhangsan)           

注意到這裡

(-name_s:zhangsan)

代表的是MUST NOT,實際意義是文檔集中不應該有name_s:zhangsan的資料,但實際是有的,是以這個子查詢傳回0條資料。

參考規則5。

(-name_s:zhangsan) NA

按照規則5,兩個結果取并集,最終結果就是1,2,4

  • 示例3
age_i:10 AND -name_s:zhangsan
#找到age_i:10的資料,并且name_s不等于zhangsan,理論應該傳回2條資料,實際結果也是符合預期。           
Solr布爾查詢的使用實踐
  • 示例4
id:("1" "2" "3" "4") AND (-name_s:zhangsan OR age_i:10)           
Solr布爾查詢的使用實踐
+(id:1 id:2 id:3 id:4) +(-name_s:a age_i:[10 TO 10])           

MUST和MUST(MUST_NOT和SHOULD的組合)的組合

name_s:a => 1

age_i:[10 TO 10] => 1, 2, 4

(-name_s:a age_i:[10 TO 10]) => 2, 4

(id:1 id:2 id:3 id:4) => 1, 2, 3, 4

+(id:1 id:2 id:3 id:4) +(-name_s:a age_i:[10 TO 10]) => 2, 4

最疑惑的-符号如何解?

當使用

-

文法時,主動用

*:*

來和

-

組成一個

AND

文法。

即:

-name_s:zhangsan

轉換為如下寫法

(*:* AND -name_s:zhangsan)

那麼,我們來回顧上面的三個例子:

age_i:10 OR -name_s:zhangsan             

改成如下寫法,結果符合預期。

age_i:10 OR (*:* AND -name_s:zhangsan)           
age_i:10 OR (-name_s:zhangsan)           
age_i:10 OR (*:* AND -name_s:zhangsan)           
age_i:10 AND -name_s:zhangsan           

改成如下寫法,結果仍然符合預期

age_i:10 AND (*:* AND -name_s:zhangsan)           
id:("1" "2" "3" "4") AND (-name_s:zhangsan OR age_i:10)           

改成如下寫法,結果符合預期

id:("1" "2" "3" "4") AND ((*:* AND -name_s:zhangsan) OR age_i:10)           

參考文檔

https://lucidworks.com/post/why-not-and-or-and-not/

繼續閱讀