我正在使用Hibernate Search / Lucene维护一个非常简单的索引来按名称查找对象 - 没有花哨的东西。
我的模型类都扩展了一个类NamedModel
,它看起来基本如下:
@MappedSuperclass
public abstract class NamedModel {
@Column(unique = true)
@Field(store = Store.YES, index = Index.UN_TOKENIZED)
protected String name;
}
我的问题是,当查询名称以特定字母开头的对象的索引时,我得到BooleanQuery$TooManyClauses
异常,例如"name:l*"
。
像"name:lin*"
之类的查询可以正常运行,实际上在通配符之前使用多个字母的任何查询都可以正常工作。
在网上搜索类似的问题时,我发现人们只使用非常复杂的查询,但似乎总是会导致异常。我不想增加maxClauseCount
,因为我不认为改变限制只是因为你达到它们是一个好习惯。
这里有什么问题?
答案 0 :(得分:3)
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 Search中。在您切换到Compass;)
后,您可能会问