Lucene QueryParser противоречивое поведение - PullRequest
0 голосов
/ 08 ноября 2011

Следующая программа:

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)), чтобы избежать такого поведения?

1 Ответ

0 голосов
/ 10 ноября 2011

Другая обработка ':' - это не ошибка QueryParser, а StandardAnalyzer.На самом деле, ':' - единственный символ в вашем списке, который не считается разделителем в StandardAnalyzer.Как следствие, анализ «a: b» даст один токен «a: b», тогда как анализ «a'b» даст два токена «a» и «b».1003 *

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

...