31

我正在使用 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

在处理来自用户的查询时,防止 ParseExceptions 的最佳方法是什么?在我看来,最有用的搜索界面是始终执行查询的界面,即使它可能是错误的查询。

似乎有一些可能的互补策略:

  • 在将查询发送到 QueryProcessor 之前“清理”查询
  • 优雅地处理异常
    • 向用户显示智能错误消息
    • 也许执行一个更简单的查询,留下错误的位

对于如何执行这些策略,我真的没有什么好主意。有没有其他人解决过这个问题?有没有我不知道的“简单”或“优雅”解析器?

4

6 回答 6

44

你可以通过使用类似的东西清理查询来让 Lucene 忽略特殊字符

query = QueryParser.Escape(query)

如果您不希望您的用户在他们的查询中使用高级语法,您可以始终这样做。

如果您希望您的用户使用高级语法,但您也希望对错误更加宽容,您应该只在 ParseException 发生后进行清理。

于 2008-11-05T12:57:27.330 回答
8

Well, the easiest thing to do would be to give the raw form of the query a shot, and if that fails, fall back to cleaning it up.

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;
}

This gives the raw form of the user's query a chance to run, but if parsing fails, we strip everything except letters, numbers, spaces and underscores; then we try again. We still risk throwing ParseException, but we've drastically reduced the odds.

You could also consider tokenizing the user's query yourself, turning each token into a term query, and glomming them together with a BooleanQuery. If you're not really expecting your users to take advantage of the features of the QueryParser, that would be the best bet. You'd be completely(?) robust, and users could search for whatever funny characters will make it through your analyzer

于 2008-11-04T21:35:07.487 回答
3

仅供参考...这是我用于 .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;
}
于 2009-05-12T22:27:10.970 回答
1

我对 Lucene.net 了解不多。对于一般的 Lucene,我强烈推荐这本书Lucene in Action。对于手头的问题,这取决于您的用户。有充分的理由(例如易用性、安全性和性能)来限制用户的查询。这本书展示了使用自定义解析器而不是 QueryParser 来解析查询的方法。我赞同 Jay 关于 BooleanQuery 的想法,尽管您可以使用自定义解析器构建更强大的查询。

于 2008-11-05T12:37:32.813 回答
1

如果您不需要所有 Lucene 功能,则编写自己的查询解析器可能会更好。它并不像一开始看起来那么复杂。

于 2008-11-05T12:59:58.557 回答
1

我和你的情况一样。

这就是我所做的。我确实捕获了异常,但只是为了让错误看起来更漂亮。我不改变文字。

我还提供了一个对 Lucene 语法的解释的链接,我已经简化了一点:http:
//ifdefined.com/btnet/lucene_syntax.html

于 2008-11-04T20:03:33.990 回答