【问题标题】:How to make the Lucene QueryParser more forgiving?如何让 Lucene QueryParser 更宽容?
【发布时间】:2010-09-20 18:08:41
【问题描述】:

我正在使用 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 之前“清理”查询
  • 优雅地处理异常
    • 向用户显示智能错误消息
    • 也许执行一个更简单的查询,去掉错误的位

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

【问题讨论】:

    标签: lucene lucene.net


    【解决方案1】:

    我和你的情况一样。

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

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

    【讨论】:

      【解决方案2】:

      嗯,最简单的做法是试一试原始形式的查询,如果失败,则退回去清理它。

      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】:

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

        【讨论】:

          【解决方案4】:

          你可以让 Lucene 忽略特殊字符,方法是用类似的东西清理查询

          query = QueryParser.Escape(query)
          

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

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

          【讨论】:

          • 我遇到了 ParseException 问题,我使用了这个解决方案,因为我的用户不会使用高级语法。谢谢!
          【解决方案5】:

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

          【讨论】:

            【解决方案6】:

            仅供参考...这是我用于 .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;
            }
            

            【讨论】:

            • 这个答案基本上抄袭了之前的答案。
            • @james.garriss 我知道这个帖子早就死了,但我不得不说。虽然您可能是对的,但它帮助我确保它在 C# 中也能按预期工作。此外,此答案中的正则表达式更完整。 :)
            猜你喜欢
            • 2011-06-28
            • 2012-06-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-01
            • 2013-02-20
            • 2014-08-07
            相关资源
            最近更新 更多