2011-11-08 85 views
0

下面的程序:Lucene的QueryParser的不一致的行爲

import java.util.Arrays; 
import java.util.List; 

import org.apache.lucene.analysis.standard.StandardAnalyzer; 
import org.apache.lucene.queryParser.ParseException; 
import org.apache.lucene.queryParser.QueryParser; 
import org.apache.lucene.util.Version; 

public class LuceneTest { 

    static final List<Character> SPECIAL_CHARS = 
     Arrays.asList('\\', '+', '-', '!', '(', ')', ':', '^', '[', ']', '"', '{', '}', '~', '*', '?', '|', '&'); 

    public static void main(String[] args) throws ParseException { 
    QueryParser query = 
     new QueryParser(Version.LUCENE_31, "", new StandardAnalyzer(Version.LUCENE_31)); 


    for (char c : SPECIAL_CHARS) { 
     System.out.println(c + " -> " + query.parse("__catch_all:foo\\" + c + "bar").toString()); 
    } 
    } 

} 

給出了這樣的輸出:

\ -> __catch_all:foo __catch_all:bar 
+ -> __catch_all:foo __catch_all:bar 
- -> __catch_all:foo __catch_all:bar 
! -> __catch_all:foo __catch_all:bar 
(-> __catch_all:foo __catch_all:bar 
) -> __catch_all:foo __catch_all:bar 
: -> __catch_all:foo:bar 
^ -> __catch_all:foo __catch_all:bar 
[ -> __catch_all:foo __catch_all:bar 
] -> __catch_all:foo __catch_all:bar 
" -> __catch_all:foo __catch_all:bar 
{ -> __catch_all:foo __catch_all:bar 
} -> __catch_all:foo __catch_all:bar 
~ -> __catch_all:foo __catch_all:bar 
* -> __catch_all:foo __catch_all:bar 
? -> __catch_all:foo __catch_all:bar 
| -> __catch_all:foo __catch_all:bar 
& -> __catch_all:foo __catch_all:bar 

注意的明顯不一致有:也請注意,我轉義特殊字符(完全做與QueryParser.escape一樣)。我希望StandardAnalyzer能夠從查詢條件中去掉特殊的標點符號,並且幾乎可以在所有情況下使用。

這顯得尤爲不一致的原因是,寫有StandardAnalyzer文檔和字段文本「富:酒吧」給我一個長期場,foo和酒吧!

第二輪轉義給出了正確的結果,即有效地「foo \\:bar」;但爲什麼這隻對冒號有必要?爲什麼我需要執行QueryParser.escape(QueryParser.escape(mystring))來避免這種行爲?

回答

0

':'的不同處理不是QueryParser的錯,而是StandardAnalyzer的錯誤。實際上,':'是您的列表中唯一不被StandardAnalyzer認爲是分隔符的字符。因此,分析「a:b」將產生一個標記「a:b」,而分析「a'b」將產生兩個標記「a」和「b」。

這裏是發生了什麼:

Original String -> unescaped string -> tokens -> query

"foo\:bar" -> "foo:bar" -> [ "foo:bar" ] -> TermQuery(__catch_all, "foo:bar")

"foo\+bar" -> "foo+bar" -> [ "foo", "bar" ] -> TermQuery(__catch_all, "foo") OR TermQuery(__catch_all, "bar")

+0

這是偉大的信息,謝謝。在* write *方面,似乎StandardAnalyzer將字符串標記爲「foo bar」,這看起來不一致。 – HenryR

+0

是什麼讓你這麼想?你能提供一段代碼來顯示這個問題嗎? – jpountz