Lucene5學習之QueryParser-Query解析器

jopen 8年前發布 | 16K 次閱讀 Lucene 中文分詞 搜索引擎

Lucene已經給我們提供了很多Query查詢器,如PhraseQuery,SpanQuery,那為什么還要提供QueryParser呢?或者說設計QueryParser的目的是什么? QueryParser的目的就是讓你從眾多的Query實現類中脫離出來,因為Query實現類太多了,你有時候會茫然了,我到底該使用哪個Query實現類來完成我的查詢需求呢,所以Lucene制定了一套Query語法,根據你傳入的Query語法字符串幫你把它轉換成Query對象,你不用關心底層是使用什么Query實現類。

上面既然說到PhraseQuery和SpanQuery,那我就隨帶扯一扯這兩個Query的區別吧,我估計這是很多初學Lucene者比較困惑的問題,兩個Query都能根據多個Term進行查詢,但PhraseQuery只能按照查詢短語在文檔中出現的順序進行匹配,而不能顛倒過來匹配,比如你查詢quick lazy,而索引中出現的是xxxxxxxxlazy qucikxxxxxxx,那PhraseQuery就沒法匹配到了,這時候你就只能使用SpanQuery了,SpanQuery的inorder參數允許你設置是否按照查詢短語在文檔中出現的順序進行匹配,以及是否允許有重疊,什么叫是否允許重疊?舉個例子說明,假如域的值是這樣的:“jumps over extremely very lazy broxn dog”,而你的查詢短語是“dog over”,因為索引中dog在over后面,而你提供的查詢短語中dog卻在over前面,這與它在索引文檔中出現的順序是顛倒的,這時候你就不能使用PhraseQuery,PhraseQuery只能按出現順序匹配,這種顛倒順序匹配無法用PhraseQuery實現,把SpanQuery的inOrder設為false,就可以無視順序了,即只要你能按slop規定的步數內匹配到dog over或者 over dog都算匹配成功。而如果inOrder設為true,意思就是你只能在規定步數內匹配到dog over,而匹配到over dog不算,并且匹配過程中不能有重疊。什么叫重疊?要得到dog over,那只能把over往右移動6步,可是它跨過了dog了,即dog重疊了,意思就是你只能在兩者之間移動,不能跨越兩者的邊界進行匹配。我解釋的不知道你們能看的明白不?注意兩者的slop都是最多需要移動幾步的意思即在規定步數內達到你想要的情況。

   跑題扯了半天PhraseQuery和SpanQuery的區別,回歸正題,接著說說QueryParser的查詢語法,關于QueryParser的語法,我們還是去看Lucene的官方Wiki吧,

https://lucene.apache.org/core/2_9_4/queryparsersyntax.html

概述里提到QueryParser是通過JavaCC把用戶輸入的String轉換成Query對象,那什么是JavaCC?JavaCC就是一個非常流行的用Java寫的解析器生成器。

Before choosing to use the provided Query Parser, please consider the following:
意思就是提醒我們在選擇使用QueryParser之前請先仔細考慮下面3個問題。

1.QueryParser是為用戶輸入文本而設計的而不是你應用程序生成的文本而設計的,什么意思?意思就是你要考慮最惡劣的情況,因為用戶輸入的文本是無法預知的,你不能試圖去規范用戶輸入什么樣格式的查詢字符串,如果你正在準備這么做,請你還是去使用Query api 構建你的Query實現類吧。

2.沒有分詞的域請直接使用Query API來構建你的Query實現類,因為QueryParser會使用分詞器對用戶輸入的文本進行分詞得到N個Term,然后再根據匹配的,這點你必須清楚。

3.第3點里提示你在設計查詢表單時,對應普通的文本框可以直接使用QueryParser,但像日期范圍啊搜索關鍵字啊下拉框里選定某個值或多個值進行限定值時,請使用Query API去做。

Term:
Term直接用一個單詞表示,如“hello” ,多個Term用空格分割,如“hello java”,

Field:
可以添加上域,域和Term字符串用冒號隔開,如title:”The Right Way”,查詢多個域用or或者and連接,

如title:”The Right Way” AND text:go

Term字符串你還可以使用通配符進行模糊匹配,如title: ja*a  title:ja?a title:ja*等等

你還可以使用~字符開啟FuzzyQuery,如title:roam~ or title:roam~0.8
相似度閥值取值范圍是0-1之間,默認值是0.5,

QueryParser語法表達式還支持開啟PhraseQuery短語查詢,如title:”jakarta apache”~10

表示查詢title域中包含jakarta和apache字符且jakarta在apache前面且jakarta與apache之間間隔距離在10個間距之內(即<=10)。

當然也支持范圍查詢,title:[java to php],age[18 to 28]

你也可以單獨為某個Term設置權重,如title:java^4,默認權重都為1.

Boolean Operators即boolean操作符即or和and,用來鏈接多個Term的,如果兩個Term僅僅用空格隔開,則默認為or鏈接的,如title:java^5 and content:lucen*

當然還有+ -字符,表示必須符合和必須不符合即排除的意思,如+jakarta lucene,但注意只有一個Term的時候,不能用NOT,比如NOT “jakarta apache”是不合法的。

而這樣就可以,”jakarta apache” -“Apache Lucene”表示必須包含jakarta apache,但不能包含Apache Lucene.

當or and條件很復雜時,需要限制優先級時可以用()小括號對Term條件進行分組,如(jakarta OR apache) AND website

當對某個域的限定值有多個可以用or/and進行鏈接,也可以用()寫在一起,如title:(+return +”pink panther”),當然你也可以用and拆成title:return and title:”pink panther”

Lucene中需要進行轉義的特殊字符包括:

+ – && || ! ( ) { } [ ] ^ ” ~ * ? : \

QueryParser使用示例如下:

QueryParser parser = new QueryParser(fieldName, new IKAnalyzer());
Query query = parser.parse(queryString);

queryString即為上面解釋的那些queryParser查詢表達式。

但QueryParser并不能完全代替Query API,它并不能實現所有Query實現類的功能,比如它不支持SpanQuery.

上面說的都是在單個域中查詢,當然要在多個域中查詢你可以使用or/and進行拼接,如果要在多個域中進行查詢,你除了用or/and拼接以外,多了另一種選擇,它就是MultiFieldQueryParser.我想Google大家都用過,Google的搜索界面就為我們提供了一個搜索輸入框,用戶只需要輸入搜索關鍵字即可,而不用關心我輸入的搜索關鍵字接下來會在哪些域(Field)里去查找,可能底層我們的索引會建立title,content,category等各種域,會依次從這幾個域中去匹配是否有符合用戶輸入的查詢關鍵字,但這些對用戶都是透明的,用戶也沒必要去了解這些, MultiFieldQueryParser就是用來解決這種多域查詢問題的。

public MultiFieldQueryParser(String[] fields, Analyzer analyzer, Map

      
  boosts) {
    this(fields, analyzer);
    this.boosts = boosts;
  }


  

這是MultiFieldQueryParser的構造函數,首先fields毫無疑問就是提供一個域名稱數組即你需要在哪些域中進行查詢,analyzer即分詞器對象,用戶輸入的搜索關鍵字我們需要對其分詞,為什么要分詞?因為用戶輸入的搜索關鍵字可能是一句話,比如:我女朋友要跟我分手,我該怎么辦,分詞后可能得到的只有兩個關鍵字就是女朋友和分手,其他都是停用詞被剔除了。最后一個boosts參數是一個map對象,是用來設置每個域的權重加權值的,map的key就是域名稱,value就是加權值。boosts參數可以不傳入,你傳入一個null也行,不傳入即表示不進行特殊加權,則默認權重加權值都是1.

來自: http://h2ex.com/632

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!