有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用通配符查询时,java BooleanQuery$Toomanycauses异常

我使用HibernateSearch/Lucene来维护一个非常简单的索引,以便按名称查找对象—这不是什么新奇的东西

我的模型类都扩展了一个类NamedModel,基本上如下所示:

@MappedSuperclass
public abstract class NamedModel {
    @Column(unique = true)
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    protected String name;
}

我的问题是,当查询名称以特定字母开头的对象(例如"name:l*")的索引时,会出现BooleanQuery$TooManyClauses异常。 像"name:lin*"这样的查询可以正常工作,事实上,任何在通配符之前使用多个字母的查询都可以工作

在网上搜索类似的问题时,我只发现人们使用非常复杂的查询,这似乎总是导致异常。我不想增加maxClauseCount,因为我认为仅仅因为达到了限制就改变限制不是一个好的做法

这里有什么问题


共 (1) 个答案

  1. # 1 楼答案

    Lucene试图将您的查询从简单的name:l*重写为所有术语都以l开头的查询(类似于name:lou OR name:la OR name: ...)——我相信这是为了更快

    作为解决方法,您可以使用ConstantScorePrefixQuery而不是PrefixQuery

    // instead of new PrefixQuery(prefix)
    new ConstantScoreQuery(new PrefixFilter(prefix));
    

    但是,这会改变文档的评分(因此,如果您依赖评分进行排序,则会进行排序)。当我们面临需要得分(和提升)的挑战时,我们决定寻找一种解决方案,如果可能的话,我们使用PrefixQuery,如果需要的话,我们可以回退到ConstantScorePrefixQuery

    new PrefixQuery(prefix) {
      public Query rewrite(final IndexReader reader) throws IOException {
        try {
          return super.rewrite(reader);
        } catch (final TooManyClauses e) {
          log.debug("falling back to ConstantScoreQuery for prefix " + prefix + " (" + e + ")");
          final Query q = new ConstantScoreQuery(new PrefixFilter(prefix));
          q.setBoost(getBoost());
          return q;
        }
      }
    };
    

    (作为一种增强,可以使用某种LRUMap来缓存以前失败的术语,以避免再次进行代价高昂的重写)

    不过,我无法帮助您将其集成到Hibernate搜索中。切换到Compass;)后,您可能会问