Как сделать Lucene QueryParser более щадящим? - PullRequest
30 голосов
/ 04 ноября 2008

Я использую Lucene.net, но я отмечаю этот вопрос для версий .NET и Java, потому что API одинаков, и я надеюсь, что есть решения на обеих платформах.

Я уверен, что другие люди обращались к этой проблеме, но я не смог найти хороших обсуждений или примеров.

По умолчанию Lucene очень требователен к синтаксису запросов. Например, я только что получил следующую ошибку:

[ParseException: Cannot parse 'hi there!': Encountered "<EOF>" at line 1, column 9.
Was expecting one of:
    "(" ...
    "*" ...
    <QUOTED> ...
    <TERM> ...
    <PREFIXTERM> ...
    <WILDTERM> ...
    "[" ...
    "{" ...
    <NUMBER> ...
    ]
   Lucene.Net.QueryParsers.QueryParser.Parse(String query) +239

Каков наилучший способ предотвращения исключений ParseException при обработке запросов от пользователей? Мне кажется, что наиболее используемый интерфейс поиска - это интерфейс, который всегда выполняет запрос, даже если он может быть неправильным.

Похоже, есть несколько возможных и взаимодополняющих стратегий:

  • «Очистить» запрос перед отправкой в ​​QueryProcessor
  • Изящно обрабатывать исключения
    • Показывать интеллектуальное сообщение об ошибке пользователю
    • Возможно, выполнить более простой запрос, исключив ошибочный бит

У меня нет действительно хороших идей о том, как реализовать любую из этих стратегий. Кто-нибудь еще обращался к этой проблеме? Есть ли какие-нибудь "простые" или "изящные" парсеры, о которых я не знаю?

Ответы [ 6 ]

43 голосов
/ 05 ноября 2008

Yo может заставить Lucene игнорировать специальные символы, очистив запрос чем-то вроде

query = QueryParser.Escape(query)

Если вы не хотите, чтобы ваши пользователи когда-либо использовали расширенный синтаксис в своих запросах, вы можете делать это всегда.

Если вы хотите, чтобы ваши пользователи использовали расширенный синтаксис, но вы также хотите быть более прощающими с ошибками, вы должны очищать их только после возникновения ParseException.

8 голосов
/ 05 ноября 2008

Что ж, самое простое, что нужно сделать, - это обработать необработанную форму запроса, а в случае неудачи вернуться к ее очистке.

Query safe_query_parser(QueryParser qp, String raw_query)
  throws ParseException
{
  Query q;
  try {
    q = qp.parse(raw_query);
  } catch(ParseException e) {
    q = null;
  }
  if(q==null)
    {
      String cooked;
      // consider changing this "" to " "
      cooked = raw_query.replaceAll("[^\w\s]","");
      q = qp.parse(cooked);
    }
  return q;
}

Это дает возможность выполнения необработанной формы пользовательского запроса, но в случае сбоя анализа мы удаляем все, кроме букв, цифр, пробелов и подчеркиваний; тогда мы попробуем еще раз. Мы все еще рискуем выбросить ParseException, но мы резко сократили шансы.

Вы могли бы также рассмотреть возможность токенизации пользовательского запроса, превратить каждый токен в запрос запроса и объединить их с BooleanQuery. Если вы не ожидаете, что ваши пользователи воспользуются функциями QueryParser, это будет лучшим выбором. Вы были бы полностью (?) Надежными, и пользователи могли бы искать любые забавные символы, которые сделают это через ваш анализатор

3 голосов
/ 13 мая 2009

К вашему сведению ... Вот код, который я использую для .NET

private Query GetSafeQuery(QueryParser qp, String query)
{
    Query q;
    try 
    {
        q = qp.Parse(query);
    } 

    catch(Lucene.Net.QueryParsers.ParseException e) 
    {
        q = null;
    }

    if(q==null)
    {
        string cooked;

        cooked = Regex.Replace(query, @"[^\w\.@-]", " ");
        q = qp.Parse(cooked);
    }

    return q;
}
1 голос
/ 05 ноября 2008

Если вам не нужны все функции Lucene, вы могли бы пойти лучше, написав свой собственный анализатор запросов. Это не так сложно, как может показаться.

1 голос
/ 05 ноября 2008

Я не знаю много о Lucene.net. Для общего Lucene, я настоятельно рекомендую книгу Lucene in Action . Для рассматриваемого вопроса это зависит от ваших пользователей. Существуют веские причины, такие как простота использования, безопасность и производительность, для ограничения запросов ваших пользователей. В книге показаны способы анализа запросов с использованием пользовательского анализатора вместо QueryParser. Я придерживаюсь второй идеи Джея о BooleanQuery, хотя вы можете создавать более сильные запросы, используя собственный анализатор.

1 голос
/ 04 ноября 2008

Я в той же ситуации, что и вы.

Вот что я делаю. Я ловлю исключение, но только для того, чтобы ошибка выглядела красивее. Я не изменяю текст.

Я также даю ссылку на объяснение синтаксиса Lucene, который я немного упростил: http://ifdefined.com/btnet/lucene_syntax.html

...