0

以下程序:

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:bar”字段文本编写文档会给我一个两个词的字段,foo 和 bar!

第二轮转义给出了正确的结果,即有效地 "foo\\:bar"; 但为什么这仅对冒号是必要的?为什么我需要做 QueryParser.escape(QueryParser.escape(mystring)) 来避免这种行为?

4

1 回答 1

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")

于 2011-11-10T13:51:09.687 回答